-
Notifications
You must be signed in to change notification settings - Fork 367
Observable interval appears to leak #259
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
FWIW wrote up a comparison test in my usual language (c++) and couldn't replicate any leaking.
Edit: fixed code |
I have the following logging format for std logging lib. This makes print the execution thread of the I've created interval stream an consumer via the code below. timer_stream = rx.Observable.interval(1000).subscribe_on(time_pool)
timer_stream.subscribe(
lambda count: logging.info(count)) As you can see from the output every tick of interval command executes in a new thread id. I think this might be the reason of the issue. I'm using RxPY 1.6.1 version. FYI. Edit: creating a scheduler and specifying it on import rx.concurrency as rxc
time_pool = rxc.ThreadPoolScheduler(1)
timer_stream = rx.Observable.interval(1000,scheduler=time_pool)
timer_stream.subscribe(
lambda count: logging.info(count)) |
Hi, I've been running a bunch of tests with a simpler sample and a slightly different way of monitoring memory, RxPY3 (HEAD master), python 3.7.3 & linux. I must say that I'm not an expert in memory management, but I believe that the garbage collector can make memory measurements quite irrelevant (?). I have no idea how and when python frees unused memory. Also it's not clear what the rss value really means (linux) and if it's reliable in a python context. Basically, the script consists in a function that creates one or more I've tested with 2 versions of this script:
def fn_interval_hot(dt, ninstances=1):
observables = []
disposables = []
for i in range(ninstances):
observable = rx.interval(dt).pipe(ops.publish())
d = observable.subscribe(lambda _: None)
observables.append(observable)
disposables.append(d)
# connect observables
for o in observables:
o.connect()
# maintain thread alive indefinitely
while True:
time.sleep(10.0) Tests have been running with:
We can see that in every cases, rss quickly grows until it reaches an almost constant value in an asymptotic fashion. So I would say that's not that bad after all. @erikkemperman @dbrattli , |
Nice analysis! Yes, TimeoutScheduler creates a lot of threads, where recycling is certainly possible. I've been meaning to try to make a pool or something, but have not found the time for that so far. |
Perhaps we should just retire |
Yes, that's one option. I was hoping to actually try something slightly more ambitious, namely to postpone mapping scheduled items to threads until they're almost due. That way we avoid claiming threads from the pool only for them to do nothing for a relatively long time. But actually, that kind of logic might make sense for the ThreadPoolScheduler as well, and in that case I guess they could be folded into a single class. |
In this test example
which is running in 2.7.15 on Kubuntu 18.04 with RxPy 1.6.1, I'm seeing the memory of this application slowly tick upwards. The output of psutil (and the system profiler) shows memory ticking upwards, while the thread count stays constant at around 9.
Full disclosure - Python is not my usual language, so I may be a missing a language gotcha.
From having a read of an implementation (in Java) of interval I didn't believe that anything here needs to managed for memory growth - Googling on memory management for infinite sequences isn't giving me much either. Is this normal (and my code is badly written) or is there an issue here?
The text was updated successfully, but these errors were encountered: