Eric Kolotyluk
Eric Kolotyluk

Reputation: 2243

Will Project Loom Virtual Threads improve the perfomance of parallel Streams?

This is not a duplicate of How do I write a correct micro-benchmark in Java?

The question goes to the heart of Project Loom design and implementation, and whether the project has been able to speed up the performance of Java Parallel Streams or not. The question is not about bench-marking, it is about intent of Project Loom.


I am experimenting with Virtual Threads in my loom-lab project, and wanted to see if Virtual Threads are faster than Platform Threads when doing a parallel stream, but it actually seems slower.

try (var executorService = Executors.newThreadPerTaskExecutor(virtualThreadFactory)) {
    var candidates3 = LongStream.iterate(3, x -> x < count, x -> x + 2);
    time4 = System.currentTimeMillis();
    var primes3 = executorService.submit(() ->
        candidates3.parallel()
            .filter(candidate -> isPrime(candidate)).toArray()
    ).get();
    time5 = System.currentTimeMillis();
}

where ultimately I get the output (in milliseconds)

sequential time = 7546
parallel   time = 1289
virtual    time = 1388

and in general using Virtual Threads is slower than the common ForkJoinPool. Am I making some basic mistake or misunderstanding somewhere, or has Project Loom not been integrated with Java Streams yet?

Upvotes: 4

Views: 2082

Answers (1)

Eric Kolotyluk
Eric Kolotyluk

Reputation: 2243

Okay, my sense of things is that

IIUC, the real benefit of a virtual thread is when you have a blocking I/O operation. With Loom, the underlying carrier thread will continue executing other tasks while your virtual thread blocks. Before Loom, this distinction was not made - there was only one type of threads - and the blocking I/O was not a feasible option for high throughput applications, like web servers.

means that Virtual Threads are not going to give me the performance boost I was hoping for in this use case...

In my experiment, I was computing prime numbers with

  1. 7397 ms - sequential stream
  2. 1316 ms - parallel stream
  3. 1392 ms - parallel stream in the context of an Execution Service with Virtual Threads
  4. 4472 ms - Virtual Threads with executorService.invokeAll(tasks)
  5. 4338 ms - Virtual Threads created from a Stream

Cases 2 & 3 are so close in performance, they are within the margin of error.

This is not I/O bound, it is purely compute bound. Parallel Streams work exceptionally well in this case, and it's hard (impossible?) to do better. My expectation I could speed things up with Virtual Threads was a misunderstanding of how Virtual Threads are optimized. Now I know better.

If I want to demonstrate the performance advantage of Virtual Threads over Platform Threads, I need to find a better use case.

My code is posted on loom-lab in case other people want to verify my conclusions. This is a learning project, and I am learning...

Upvotes: 4

Related Questions