24429

Java 8 parallel streams don't appear to actually be working in parallel

Question:

I'm trying to use Java 8's parallelStream() to execute several long-running requests (eg web requests) in parallel. Simplified example:

List<Supplier<Result>> myFunctions = Arrays.asList(() -> doWebRequest(), ...) List<Result> results = myFunctions.parallelStream().map(function -> function.get()).collect(...

So if there are two functions that block for 2 and 3 seconds respectively, I'd expect to get the result after 3 seconds. However, it really takes 5 seconds - ie it seems the functions are being executed in sequence and not in parallel. Am I doing something wrong?

edit: This is an example. The time taken is ~4000 milliseconds when I want it to be ~2000.

long start = System.currentTimeMillis(); Map<String, Supplier<String>> input = new HashMap<String, Supplier<String>>(); input.put("1", () -> { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } return "a"; }); input.put("2", () -> { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } return "b"; }); Map<String, String> results = input.keySet().parallelStream().collect(Collectors.toConcurrentMap( key -> key, key -> { return input.get(key).get(); })); System.out.println("Time: " + (System.currentTimeMillis() - start)); }

Doesn't make any difference if I iterate over the entrySet() instead of the keySet()

edit: changing the parallel part to the following also does not help:

Map<String, String> results = input.entrySet().parallelStream().map(entry -> { return new ImmutablePair<String, String>(entry.getKey(), entry.getValue().get()); }).collect(Collectors.toConcurrentMap(Pair::getLeft, Pair::getRight));

Answer1:

When executing in parallel, there is overhead of decomposing the input set, creating tasks to represent the different portions of the calculation, distributing the actions across threads, waiting for results, combining results, etc. This is over and above the work of actually solving the problem. If a parallel framework were to always decompose problems down to a granularity of one element, for most problems, these overheads would overwhelm the actual computation and parallelism would result in a slower execution. So parallel frameworks have some latitude to decide how finely to decompose the input, and that's what's happening here.

In your case, your input set is simply too small to be decomposed. So the library chooses to execute sequentially.

Try this on your four-core system: compare

IntStream.range(0, 100_000).sum()

vs

IntStream.range(0, 100_000).parallel().sum()

Here, you're giving it enough input that it will be confident it can win through parallel execution. If you measure with a responsible measurement methodology (say, the JMH microbenchmark harness), you'll probably see an almost-linear speedup between these two examples.

Recommend

  • SQL Last 6 Months
  • Any place where i can find free flash tutorials [closed]
  • How to consume WCF on windows server 2000 OS?
  • ms access 2000 changing linked tables without using Linked table manager
  • Slow two-table query in SQL Server
  • SQL: extract date from string
  • Update statement error: Subquery returned more than 1 value
  • Calculate Sum From Moving 4 Rows in SQL
  • Solving Readers/Writers using java Semaphores
  • Synchronizing a crowd in Java
  • Thread Synchronization - Synchronizing three threads to print 012012012012… not working
  • ExtJS 4 Spring 3 file upload. Server sends bad response content type
  • Hadoop (java) change the type of Mapper output values
  • How to clear out the contents of a map when clear() method call throws UnsupportedOperationException
  • Update Search Results to Lazy Adapter in android
  • How to apply async task into this
  • Is the Go HTTP handler goroutine expected to exit immediately in this case?
  • Parallel sieve of Eratosthenes - Java Multithreading
  • How to handle empty space in url when downloading image from web?
  • Problem with rejecting incoming call
  • How to copy styled text in JTextPane
  • nonblocking BIO_do_connect blocked when there is no internet connected
  • How to determine if there are bytes available to be read from boost:asio:serial_port
  • Does it make sense to call System.gc() and Thread.sleep() when working on Bitmaps?
  • Converting a WriteableBitmap image ToArray in UWP
  • Unity3D & Android: Difference between “UnityMain” and “main” threads?
  • Reading JSON from a file using C++ REST SDK (Casablanca)
  • Java: can you cast Class into a specific interface?
  • Why value captured by reference in lambda is broken? [duplicate]
  • Java Scanner input dilemma. Automatically inputs without allowing user to type
  • Spray.io: When (not) to use non-blocking route handling?
  • Volley JsonObjectRequest send headers in GET Request
  • AES padding and writing the ciphertext to a disk file
  • Updating server-side rendering client-side
  • How to extract text from Word files using C#?
  • javascript inside java/jsp code
  • what is the difference between the asp.net mvc application and asp.net web application
  • Hibernate gives error error as “Access to DialectResolutionInfo cannot be null when 'hibernate.
  • Matrix multiplication with MKL
  • Binding checkboxes to object values in AngularJs