springspring-webfluxproject-reactorreactor-nettyspring-reactor

Spring Reactor Webflux Scheduler Parallelism


For a fully non-blocking end to end reactive calls, is it recommended to explicitly call publishOn or subscribeOn to switch schedulers? For either cpu consuming or non consuming tasks, is it favorable to always use parallel flux to optimize performance?


Solution

  • For a fully non-blocking end to end reactive calls, is it recommended to explicitly call publishOn or subscribeOn to switch schedulers?

    publishOn is used when you publish data to downstream while subscribeOn is used when you consume data from upstream. So it really depends on what kind of job you want to perform.

    For either cpu consuming or non consuming tasks, is it favorable to always use parallel flux to optimize performance?

    Absolutely not, Consider this example:

    Flux.range(1, 10)
            .parallel(4)
            .runOn(Schedulers.parallel())
            .sequential()
            .elapsed()
            .subscribe(i -> System.out.printf(" %s ", i));
    

    The above code is a total waste because i will be processed almost instantly. Following code will perform better than above:

    Flux.range(1, 10)
            .elapsed()
            .subscribe(i -> System.out.printf(" %s ", i));
    

    Now consider this:

    public static <T> T someMethodThatBlocks(T i, int ms) {
        try { Thread.sleep( ms ); }
        catch (InterruptedException e) {}
        return i;
    }
    
    // some method here
    Flux.range(1, 10)
            .parallel(4)
            .runOn(Schedulers.parallel())
            .map(i -> someMethodThatBlocks(i, 200))
            .sequential()
            .elapsed()
            .subscribe(i -> System.out.printf(" %s ", i));
    

    The output is similar to:

     [210,3]  [5,1]  [0,2]  [0,4]  [196,6]  [0,8]  [0,5]  [4,7]  [196,10]  [0,9] 
    

    As you can see that first response came in after 210 ms, followed by 3 responses with near 0 elapsed time in between. The cycle is repeated again and again. This is where you should be using parallel flux. Note that creating more number of threads doesn't guarantee performance because when there are more number of threads then context switching adds alot of overhead and hence the code should be tested well before deployment. If there are alot of blocking calls, having more than 1 number of thread per cpu may give you a performance boost but if the calls made are cpu intensive then having more than one thread per cpu will slow down the performance due to context switching.

    So all in all, it always depends on what you want to achieve.