簡體   English   中英

番石榴EventBus調度

[英]Guava EventBus dispatching

我正在使用Guava的EventBus來啟動一些處理和報告結果。 這是一個非常簡單的可編譯示例:

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());
    }
}

我將這些事件用作其他軟件組件的一種方式,以便為此處理做准備。 例如,他們可能必須在處理之前保存其當前狀態並在之后恢復它。

我希望這個程序的輸出是:

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

應該指示處理已經開始的事件實際發生在實際處理之后(“生成結果”)。

查看源代碼后,我理解為什么它會以這種方式運行。 這是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事件類似,在所有處理程序完成之前調用事件不會返回。

我不太明白這個實現的原因。 當然,事件保證是有序的,但周圍代碼的順序完全失真。

有沒有辦法讓總線按照描述運行並產生所需的輸出? 我確實讀過Javadocs

EventBus保證它不會同時從多個線程調用訂閱者方法,除非該方法通過承載@AllowConcurrentEvents批注明確允許它。

但我不認為這適用於此 - 我在單線程應用程序中看到了這個問題。

編輯

這里的問題的原因是我post ING從用戶中。 由於事件總線不可重入,因此這些“子帖子”排隊並在第一個處理程序完成后處理。 我可以注釋掉if (isDispatching.get()) { return; } if (isDispatching.get()) { return; }在部分EventBus源和一切行為與我所期望的-所以真正的問題是什么潛在的問題,我已介紹了這樣做? 似乎設計師做出了一個盡責的決定,不允許重入。

EventBus通常基於以下原則運行:將事件發布到總線的代碼不應關心訂戶對事件的處理方式,也不關心事件被發布的順序(在同步事件的情況下)巴士無論如何)。

如果您希望在方法過程中的特定時間調用特定方法,並且希望確保在方法繼續之前完成這些方法(如您在示例中所示),為什么不直接調用這些方法? 當您使用事件總線時,您明確地將代碼與響應給定事件的確切事件分開。 這在許多情況下是可取的,並且是EventBus存在的主要原因,但它似乎並不是你想要的。

我試着總結一下Guava的EventBus事件傳遞行為:

如果在時刻t1發布事件E1 ,則通知所有訂戶。 如果其中一個訂閱者在其@Subscribe -method中發布了一個事件本身(稍后一刻),那么“新”事件E2將被排隊並隨后發送。 之后意味着:畢竟@Subscribe -tthods for E1 from t1確實返回了。

將這種“級聯”事件發布與廣度優先樹遍歷進行比較。

它似乎是EventBus的明確選擇設計。

雖然發布到EventBus不會返回,直到所有“訂閱者”都已發出信號。這些訂閱者可能尚未開始執行。 這意味着當第一個bus.post返回時,您繼續下一個帖子,而沒有任何干預用戶開始處理。

public void post(Object event)將事件發布給所有注冊用戶。 事件發布到所有訂閱者后,此方法將成功返回,並且無論訂閱者拋出任何異常。 如果沒有訂閱者訂閱了事件的類,並且事件不是DeadEvent,它將被包裝在DeadEvent中並重新發布。

參數:event - 要發布的事件。

我知道這個問題已經有4年了,但我今天遇到了同樣的問題。 有一個簡單(和反直覺)的變化來獲得你想要的行為。 根據https://stackoverflow.com/a/53136251/1296767 ,您可以將AsyncEventBus與DirectExecutor一起使用:

public static EventBus bus = new AsyncEventBus(MoreExecutors.newDirectExecutorService());

使用上述更改運行測試代碼,結果正是您想要的:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM