2

I was testing the performance of java 8 parallel stream api by creating a simple loop and adding elements in an array.

I am getting a huge performance boost over non parallel one.

But when I am checking my task manager I am seeing an uncontrolled CPU usage, it eats up all my CPU during that period. Check the CPU usage

here is my sample code,

    public static void withIfElse(boolean sorted) {

    int[] arr = new int[32768];
    Random rand = new Random();
    for(int i = 0;i < arr.length;i++)
        arr[i] = rand.nextInt(256);
    if(sorted)
        Arrays.parallelSort(arr);

    long nst = System.currentTimeMillis();
    long sum = 0;
    for(int j=0;j<100000;j++) {
        sum += Arrays.stream(arr).parallel().filter(m->m>=128).reduce((m,n)-> m+n).getAsInt();
    }

    System.out.printf("Time taken for boolean %b is %d ms. \n",sorted,(System.currentTimeMillis()-nst));

}

I am able to achieve almost 2x to 8x performance boost.

But ,

Cpu usage is uncontrolled. Is there any way to force java to only 2 cores ?

I have also tried setting

System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "1");

But still CPU usage is high.

Also is it recommended to use parallel stream?, because suppose in my application I have 10 user threads, or a web application where each request is a thread, in that case if I start a parallel stream on multiple threads which eventually eat all my cpu, there will be so many context switching.

Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
RBanerjee
  • 957
  • 1
  • 9
  • 18
  • Parallel streams have pros and cons. Nobody can tell you if the pros outweigh the cons for *you*. You should study the concepts, and see how they help with your workload. We can't tell you that. – GhostCat Jun 17 '17 at 18:47
  • But uncontrolled CPU usage is bad. and parallel is not asking for any input for no of cores to be used. – RBanerjee Jun 17 '17 at 18:49
  • 1
    Point is: some operations can be executed *faster* by dividing the problem and running multiple threads in parallel on subsets. You get results quicker - but don't expect that to come for free. And if you are looking for throttling CPU usage, I would rather recommend concepts like cgroups for example. The JVM will simply consume as much CPU power as it can. – GhostCat Jun 17 '17 at 18:53
  • 1
    Re, "Uncontrolled CPU usage is bad." That may be the case for _your_ application, but that is not the case for every application. Some people want to do big computations. CPUs cost money, and they want to be able to use 100% of what they paid for. – Solomon Slow Jun 17 '17 at 19:33
  • Believe it or not, in a time not so long ago, there was only one CPU in a system and it always ran at 100% as long as there was work to do. Fairness between users or processes is a job of the operating system, not of a single application. If your job really benefits from parallel processing, limiting the number of used cores just means occupying these cores for longer than necessary. That’s no win. – Holger Jun 19 '17 at 10:16
  • So what will happen if all the cores are occupied for long time, can it make OS unresponsive ? Also how will it behave if cores are already occupied by other processes. – RBanerjee Jun 19 '17 at 14:41
  • The operating system can schedule an arbitrary number of processes or threads on each core, just like it did in the single core era. It’s up to the os, which strategy it uses, usually it will give precedence to the tasks which did not occupy the core for so long, which will raise responsiveness. – Holger Jun 19 '17 at 16:37

3 Answers3

3

My 0.02$: huge performance boost over non parallel one. huge is probably a bit too much here. And there might be good reasons for this - first, the way you test. It is so critical that there has been a question with over 500 up-votes especially for this: micro-benchmark. You might think you have good tests written, but jvm could have different plans for you.

For moderate data, indeed a sequential stream might be faster than a parallel one. It's a lot more work that has to be done by a parallel stream. But without actual measurements, it's close to impossible to say; but here are recommendations from the best in the field, like this.

When you say that the you want to limit java to some cores - the plain answer is that you can't; from java code that is. It has to be done from the OS, if it doable at all. What you have enable there via java.util.concurrent.ForkJoinPool.common.parallelism is limiting the threads, not the cores.

And a single thread can be split over multiple cpus - it depends on the Operating system itself.

Eugene
  • 117,005
  • 15
  • 201
  • 306
1

Parallel streams run, by default, in the system-wide ForkJoinPool, which gives one thread for each core available on your machine.

If you want to change this behaviour, you can run your parallel stream in a ForkJoinPool of your choosing:

    ForkJoinPool fjp = new ForkJoinPool(2);
    ForkJoinTask<Long> sumFuture = fjp.submit(() -> {
        long sum = 0;
        for(int j=0;j<100000;j++) {
            sum += Arrays.stream(arr).parallel().filter(m->m>=128).reduce((m,n)-> m+n).getAsInt();
        }
        return sum;
    });
Joe C
  • 15,324
  • 8
  • 38
  • 50
  • I can't really tell how you are answering OP's questions... and it seems he is already aware of system-wide pool, because of `java.util.concurrent.ForkJoinPool.common.parallelism` that he is setting – Eugene Jun 17 '17 at 20:53
0

I ran into a similar problem where my code was using parallelstreams(). The problem with parallel stream is that it utilises all the CPU cores. I have a system of 48 cores. Below is the screenshot of CPU utilization.enter image description here

To make the parallestream use less CPU i changed the number of parallelism in the ForkJoinCommonPool while submitting my jar using the below command in CLI

java -Djava.util.concurrent.ForkJoinPool.common.parallelism=20 -jar <jar-name>

After this my CPU utilization picture looks like below enter image description here

kushagra deep
  • 462
  • 6
  • 12