ab m
ab m

Reputation: 422

Are Reactor operators like flatMap() that runs on same main thread any more efficient than regular blocking code?

I understand that a lot of reactor operators like flatMap() run on the same thread on which the onNext method was invoked. What I am trying to understand is if such a method is any more efficient/performant non-blocking than a regular blocking call in say a for loop. Sorry if it's a noob question but I can't seem to grasp it. Is the power of reactive realized only when we use Schedulers that jump threads (e.g. Schedulers.parallel()) and so on?

e.g. if I had a function like the following

List<Integer> integers = Arrays.asList(5,6,7,8,9,10);
    Flux.fromIterable(integers)
            .flatMap(this::makeAReactiveMethodCall)
            .subscribe(r -> log.info(Thread.currentThread().getName()));

Logs look something like this - notice all the threads are the same "main" one.

01:25:40.641 INFO ReactiveTest - main
01:25:40.642 INFO ReactiveTest - main
01:25:40.642 INFO ReactiveTest - main
01:25:40.642 INFO ReactiveTest - main
01:25:40.642 INFO ReactiveTest - main
01:25:40.642 INFO ReactiveTest - main

All invocations happen on the same main thread. How is this code more efficient than making all the call in a for loop with blocking semantics? Say the following code?

integers.forEach(i -> this.makeAReactiveMethodCall(i).block());

Upvotes: 0

Views: 1030

Answers (2)

lkatiforis
lkatiforis

Reputation: 6255

Assuming each makeAReactiveMethodCall does some I/O and takes 1 second to complete. Using the flatMap operator your calls will be made asynchronously. This means that the main thread will make all 6 calls without waiting for the I/O operation to complete(non-blocking), instead, it will process some other work and will be notified when a call is completed. In the case of WebClient and Project Reactor, this is achieved by using the Netty event loop to queue/dispatch/process events.

In the traditional, blocking way(eg. RestTemplate), it would take 6 seconds to make all 6 calls synchronously. Of course, you could use ExecutorService API to make it asynchronously, but in that case, you would need 6 threads because calls would be blocking. One of the advantages of the reactive model is that number of threads is limited, thus, resources are not wasted in multiple thread creation.

Upvotes: 2

Simon Basl&#233;
Simon Basl&#233;

Reputation: 28301

it's not if makeReactiveMethodCall() is doing CPU-bound work, or if it is not really reactive at all but a blocking call in disguise.

it's more efficient the moment makeReactiveMethodCall introduces some latency, eg. by performing I/O in a reactive manner.

there is also a tradeoff in composition and using a unified abstraction for your various processing steps that you might want to consider.

but if you're after pure throughput of CPU-bound code, then by all means use a good old loop.

Upvotes: 1

Related Questions