scijava-common
scijava-common copied to clipboard
DefaultEventBus#publishLater should use queue instead of run
@dscho and @ctrueden -
Is it possible that having publishLater
call EventService#run
instead of EventService.queue
could be violating some assumptions in IJ2?
At the least we should probably document the various publish
methods in DefaultEventBus
, as I'm not sure the expected behavior of a publishLater
method would be to run it immediately on a new thread - especially given that publishNow
uses ThreadService#invoke
which appears to only run threads on the EDT... so the behavior of these two methods seems reversed/counter-intuitive without documentation.
Yes, as we discussed @hinerm, I think 6b878da41160da695f6552ee86f537cff2443faf was an error because the contract of publish
, publishNow
and publishLater
is for them to always execute things on the EDT (for some definition of "EDT" :wink:). It may be orders of magnitude faster, but it also violates that contract, meaning that non-EDT threads now receive event notifications which has really bad ramifications.
And I agree about adding javadoc for the DefaultEventBus
API. (Tangentially: we should rename DefaultEventBus
to SciJavaEventBus
, since there is no corresponding org.scijava.event.EventBus
interface.)
Whatever we do, we must not have the performance regression that adds a couple of seconds to the Context creation just because events are published synchronously...
@dscho: It would not be a "regression" because the "fix" that "improved performance" actually broke behavior. By the same logic, I could simply change the Context()
constructor to call this(true)
instead of this(false)
, claim an orders-of-magnitude "performance increase" and then call it a "performance regression" when someone inevitably reverts that broken change.
However, that said, of course I agree wholeheartedly that we should do whatever we can to avoid such high overhead when publishing events. But not at the cost of correctness—the event subsystem is too critical for that.
A compromise, then. Start a thread that adds a thread to the EDT. So that the 100ms do not punish the current thread.
@dscho: Sure, if doing that is truly faster, then I'm all for it. It's bizarre to me that calling EventQueue.invokeLater
directly pays such a heavy price. :sweat:
Years later, this rears its head again. When debugging some status-reporting issue with @etadobson, we noticed that dozens of new threads were spawned—in fact one per call to statusService.updateStatus(...)
, because it publishes a StatusEvent
which in turn calls EventService#publishLater
which (contrary to documentation) then calls ThreadService#run
rather than ThreadService#queue
. I'm going to escalate this to a bug finally, and will try to find time to implement Johannes's suggestion above to spawn a thread that queues the event to the EDT, and then test how it impacts both behavior and performance.