Java 8 parallel performance trap flow

Parallelization stream is divided into a plurality of blocks, each block is processed independently, the results are summarized at the end.

CPU-intensive code is as follows:

 

private long countPrimes(int max) {
    return range(1, max).parallel().filter(this::isPrime).count();
}
private boolean isPrime(long n) {
    return n > 1 && rangeClosed(2, (long) sqrt(n)).noneMatch(divisor -> n % divisor == 0);
}

 The number of prime numbers between 1 and a maximum value countPrimes calculated. Range digital stream created by the method, is switched to the parallel mode, to filter out non-prime number, the total number of the remaining calculations. Because isPrime method is extremely ineffective and take up a lot of CPU, we can use parallelism and take advantage of all available CPU cores.

 

Let's look at another example:

 

private List<StockInfo> getStockInfo(Stream<String> symbols) {
     return symbols.parallel()
            .map(this::getStockInfo) //slow network operation
            .collect(toList());
}

Enter a ticker symbol list, we must call a slow network operations to get some details about the stock. Here, we do not deal CPU-intensive operations, but we can also use parallelization. Request parallel execution of multiple networks is a good idea. Similarly, a good flow of task parallelism, do you agree?

 

If you do so, please see the previous example again. There is a big mistake. Did you see it? The problem is that all parallel streams using a common fork-join the thread pool . If you submit a long-running task, it will effectively block all threads in the pool. Therefore, you will block all other tasks in parallel streams.

 

Imagine servlet environment, when a request to call getStockInfo (), another request call countPrimes (). Even if each requiring different resources, it will prevent another. Worse, you can not specify a parallel flow thread pool; the entire class loader must use the same.

 

Let's explain it in the following example:

 

private void run() throws InterruptedException {
 ExecutorService es = Executors.newCachedThreadPool();
 // Simulating multiple threads in the system
 // if one of them is executing a long-running task.
 // Some of the other threads/tasks are waiting
 // for it to finish
 es.execute(() -> countPrimes(MAX, 1000));
 //incorrect task
 es.execute(() -> countPrimes(MAX, 0));
 es.execute(() -> countPrimes(MAX, 0));
 es.execute(() -> countPrimes(MAX, 0));
 es.execute(() -> countPrimes(MAX, 0));
 es.execute(() -> countPrimes(MAX, 0));
 es.shutdown();
 es.awaitTermination(60, TimeUnit.SECONDS);
}
private void countPrimes(int max, int delay) {
  System.out.println( range(1, max).parallel() .filter(this::isPrime).peek(i -> sleep(delay)).count() );

}

 

Here, we simulate six threads in the system. All of which are executed by the CPU-intensive tasks, the first to be "suspended", after it finds prime slept for a second. This is just a contrived example; you can imagine being stuck or perform a blocking operation of the thread.

 

The question is: what happens when this code is executed? We have six tasks; one would need a full day to complete, and the rest should be completed more quickly. Not surprisingly, every time the code is executed, will get different results. You want to have such behavior in a production system do? Dusseldorf a task canceled the rest of the application? I guess not.

 

On how to ensure that such things do not always happen, only two choices. The first is to ensure that all tasks submitted to the Public fork-join pools are not card, must be completed within a reasonable time. But this is easier said than done, especially in complex applications.

 

Another option is to not use parallel streams, and wait for Oracle allows us to specify the thread pool parallel streams.

Guess you like

Origin www.cnblogs.com/java1024/p/11356622.html
Recommended