番石榴EventBus调度 [英] Guava EventBus dispatching

查看:163
本文介绍了番石榴EventBus调度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Guava的EventBus进行一些处理并报告结果.这是一个非常简单的可编译示例:

I'm using Guava's EventBus to kick off some processing and report results. Here's a very simple compilable example:

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;

public class Test {

    public static class InitiateProcessing { }
    public static class ProcessingStarted { }
    public static class ProcessingResults { }
    public static class ProcessingFinished { }

    public static EventBus bus = new EventBus();

    @Subscribe
    public void receiveStartRequest(InitiateProcessing evt) {
        System.out.println("Got processing request - starting processing");
        bus.post(new ProcessingStarted());

        System.out.println("Generating results");
        bus.post(new ProcessingResults());
        System.out.println("Generating more results");
        bus.post(new ProcessingResults());

        bus.post(new ProcessingFinished());
    }

    @Subscribe
    public void processingStarted(ProcessingStarted evt) {
        System.out.println("Processing has started");
    }

    @Subscribe
    public void resultsReceived(ProcessingResults evt) {
        System.out.println("got results");
    }

    @Subscribe
    public void processingComplete(ProcessingFinished evt) {
        System.out.println("Processing has completed");
    }


    public static void main(String[] args) {
        Test t = new Test();
        bus.register(t);
        bus.post(new InitiateProcessing());
    }
}

我将这些事件用作其他软件组件做出反应以准备此处理的一种方式.例如,他们可能必须在处理之前保存其当前状态,然后在处理后将其恢复.

I use these events as a way for other software components to react in preparation for this processing. For example, they may have to save their current state before processing and restore it after.

我希望该程序的输出为:

I would expect the output of this program to be:

Got processing request - starting processing
Processing has started
Generating results
got results
Generating more results
got results
Processing has completed

实际的输出是:

Got processing request - starting processing
Generating results
Generating more results
Processing has started
got results
got results
Processing has completed

本应指示处理已开始的事件实际上发生在实际处理之后(生成结果").

The event that is supposed to indicate that processing has started actually happens after the actual processing ("generating results").

查看源代码后,我了解了为什么这样做.这是相关的EventBus的代码.

After looking at the source code, I understand why it's behaving this way. Here's the relevant source code for the EventBus.

  /**
   * Drain the queue of events to be dispatched. As the queue is being drained,
   * new events may be posted to the end of the queue.
   */
  void dispatchQueuedEvents() {
    // don't dispatch if we're already dispatching, that would allow reentrancy
    // and out-of-order events. Instead, leave the events to be dispatched
    // after the in-progress dispatch is complete.
    if (isDispatching.get()) {
        return;
    }
    // dispatch event (omitted)

发生了什么事,因为我已经在分派顶级InitiateProcessing事件,其余事件才被推送到队列的末尾.我希望它的行为与.NET事件类似,在所有处理程序完成之前,调用事件不会返回.

What's happening is since I'm already dispatching the top level InitiateProcessing event, the rest of the events just get pushed to the end of the queue. I would like this to behave similar to .NET events, where invoking the event doesn't return until all handlers have completed.

我不太了解这种实现的原因.当然,可以保证事件是按顺序进行的,但是周围代码的顺序会完全失真.

I don't quite understand the reason for this implementation. Sure, the events are guaranteed to be in order, but the order of the surrounding code gets completely distorted.

是否有任何方法可以使总线表现出所描述的状态并产生所需的输出?我确实在Javadocs中读到了

Is there any way to get the bus to behave as described and produce the desired output? I did read in the Javadocs that

EventBus保证不会从中调用订户方法 除非该方法明确允许,否则将同时运行多个线程 它带有@AllowConcurrentEvents注释.

The EventBus guarantees that it will not call a subscriber method from multiple threads simultaneously, unless the method explicitly allows it by bearing the @AllowConcurrentEvents annotation.

但是我不认为这适用于这里-我在单线程应用程序中看到了这个问题.

But I don't think this applies here - I'm seeing this issue in a single threaded application.

修改

这里出现问题的原因是我在订阅者内部post.由于事件总线不是可重入的,因此这些子帖子"将排队,并在第一个处理程序完成后进行处理.我可以在EventBus源代码中的if (isDispatching.get()) { return; }部分中注释掉,并且一切都按我的预期进行-因此,真正的问题是这样做带来了哪些潜在问题?设计师似乎做出了认真的决定,不允许再次进入.

The cause of the issue here is that I'm posting from within a subscriber. Since the event bus is not reentrant, these "sub-posts" get queued up and are handled after the first handler completes. I can comment out the if (isDispatching.get()) { return; } section in the EventBus source and everything behaves as I would expect - so the real question is what potential problems have I introduced by doing so? It seems the designers made a conscientious decision to not allow reentrancy.

推荐答案

EventBus通常基于以下原则运行:将事件发布到总线上的代码不必关心订户对事件的处理方式或时间,其他而不是遵守事件发布的顺序(无论如何,对于同步事件总线).

EventBus generally operates on the principle that the code posting an event to the bus shouldn't care about what the subscribers do with the events or when, other than that the order the events were posted in is respected (in the case of a synchronous event bus anyway).

如果您希望在方法执行过程中的特定时间调用特定方法,并且希望确保在方法继续执行之前完成这些方法(就像您在示例中所看到的那样),为什么不直接调用这些方法呢?当使用事件总线时,您需要将代码与响应给定事件的确切结果明确分开.在许多情况下,这是理想的选择,这是EventBus存在的主要原因,但这似乎并不是您想要的.

If you want specific methods to be called at specific times in the course of your method and you want to be sure those methods complete before your method continues (as you seem to in your example), why not call those methods directly? When you use an event bus, you're explicitly separating your code from what exactly happens in response to a given event. This is desirable in many cases and is the main reason EventBus exists, but it doesn't seem to be quite what you want here.

这篇关于番石榴EventBus调度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆