Use EventLoopScheduler for timeout operator - #748
Conversation
|
Thanks for the PR — the underlying problem is real: That said, I think this particular fix introduces two concrete regressions, and it also only addresses one of ~20 places with the same issue. Blocking issues1. Deadlock: a single shared thread runs user callbacks inline
Reproduced against current import threading
import reactivex
from reactivex import operators as ops
from reactivex.scheduler import EventLoopScheduler
sched = EventLoopScheduler() # simulates the PR's module-level default
done = threading.Event()
def on_err(e):
print("outer timeout fired, now running a nested timeout...", flush=True)
try:
reactivex.never().pipe(ops.timeout(0.5, scheduler=sched)).run()
except Exception as ex:
print("nested completed:", ex, flush=True)
done.set()
reactivex.never().pipe(ops.timeout(0.5, scheduler=sched)).subscribe(on_error=on_err)
print("nested finished in time:", done.wait(5), flush=True)The same code with 2. Unbounded queue growth on hot streams
sched = EventLoopScheduler()
s = Subject()
sub = s.pipe(ops.timeout(60.0, scheduler=sched)).subscribe(lambda v: None)
for i in range(20000):
s.on_next(i)
print("pending items in event loop queue:", len(sched._queue))
# pending items in event loop queue: 20001Every Secondary concerns
Suggested directionNote:
|
Each instance of
reactivex.operators.timeoutconsumes a thread for the duration of the timeout period. This can add up and cause thread exhaustion with heavy use.Using
EventLoopScheduleris appropriate for this use case because we schedule a tiny amount of work usingscheduler.schedule_absoluteorscheduler.schedule_relative.