简体   繁体   English

Mono.defer() 的实际情况是什么?

[英]What is the real world case for Mono.defer()?

I know what Mono.defer() does do, but when should I use it?我知道Mono.defer()做什么,但我应该什么时候使用它? I know that one of the use cases is to defer some blocking side effects in functions that return Mono , but that's generally a bad practice (putting side effects in functions that return Mono or Flux ).我知道其中一个用例是推迟返回Mono函数中的一些阻塞副作用,但这通常是一种不好的做法(将副作用放在返回MonoFlux函数中)。 And when I want to wrap some blocking code within the Mono there's Mono.fromCallable() .当我想在Mono包装一些阻塞代码时,有Mono.fromCallable() So what is the best case to use Mono.defer() ?那么使用Mono.defer()的最佳情况是什么?

Mono.fromCallable() is for regular deferred service call. Mono.fromCallable()用于常规的延迟服务调用。 The Mono.defer() produces a Mono and it does that only when you subscribe . Mono.defer()产生一个Mono并且它只有在您subscribe时才Mono.defer() So, you may decide to create this or that Mono not during composition phase, but exactly on the target subscribe.因此,您可以决定不在组合阶段创建这个或那个Mono ,而是完全在目标订阅上创建。

@a.khakh

A very simple use case that helped me was to execute blocking code in another thread, that is, to process that blocking call so that the main-thread would not block me.帮助我的一个非常简单的用例是在另一个线程中执行阻塞代码,即处理该阻塞调用,以便主线程不会阻塞我。

I saw the need to use defer to subscribe in another thread, in this case in a Scheduler provided by project reactor and programmed by Simon Basle.我看到需要使用 defer 在另一个线程中订阅,在这种情况下,是在由项目反应器提供并由 Simon Basle 编程的调度程序中。

If you do a combination of defer plus subscribeOn and a Schedulers.boundedElastic you will make your code non-blocking or rather it will not block your application, removing contention from the main-thread.如果您将defersubscribeOnSchedulers.boundedElastic结合使用,您将使您的代码非阻塞,或者更确切地说它不会阻塞您的应用程序,从而从主线程中消除争用。


The following image shows that the third component of a Combo, internally uses a defer plus a Scheduler, so as not to block the application.下图显示了一个Combo的第三个组件,内部使用了一个defer加一个Scheduler,以免阻塞应用。

  • ignore the method called ui.access() it is part of the vaadin framework.忽略名为ui.access()的方法,它是 vaadin 框架的一部分。
Mono.defer(()  -> this.reactiveRandomNumbers.monoFrecuency(event.getValue().getSize())) <1>
                        .doOnEach(signal -> log.info("Thread name doOnNext(): {}", Thread.currentThread().getName()))
                        .subscribeOn(Schedulers.boundedElastic())
                        .subscribe(subscribeMap -> {
                            ui.access(() -> {
                                log.info("Thread name subscribe(): {}", Thread.currentThread().getName());
                                this.execute(event.getValue().getSize(), e -> subscribeMap);
                            });
                        });

Sometimes you need to calculate something synchronous lazily.有时你需要懒惰地计算一些同步的东西。

For instance, we have an asynchronous service例如,我们有一个异步服务

public interface SomeService {

    Mono<User> getUserByName(String name);

    Mono<CreateUserResult> createUser(User user);

}

and an endpoint, which looks up for the user in this service and creates if the one was not found.以及一个端点,它在此服务中查找用户并在未找到时创建。 BUT before the creation some heavy calculations must be performed in sync in special thread pool.但是在创建之前,必须在特殊线程池中同步执行一些繁重的计算。 So所以

someService.getUserByName(name)
                .switchIfEmpty(Mono.defer(() -> {
                    var someHeavyCalculatedData = localHeavyService.doSomethingNecessary(name);
                    return someService.createUser(new User(name, someHeavyCalculatedData));
                }).subscribeOn(specialScheduler));

Sure, you can say that we can use Mono.fromCallable instead and do it like当然,你可以说我们可以使用Mono.fromCallable来代替

someService.getUserByName(name)
                .switchIfEmpty(Mono.fromCallable(() -> localHeavyService.doSomethingNecessary(name))
                        .subscribeOn(specialScheduler)
                        .flatMap(someHeavyCalculatedData -> someService.createUser(new User(name, someHeavyCalculatedData)))
                );

But each method call in reactive chain causes creation of a huge amount of objects in memory.但是反应链中的每个方法调用都会导致在内存中创建大量对象。 Well for one single call you, probably won't notice anything, but with higher load frequent allocating memory, then releasing it by GC would cause your app being slow.好吧,对于一次呼叫您,您可能不会注意到任何事情,但是由于负载较高,频繁分配内存,然后通过 GC 释放它会导致您的应用程序变慢。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM