-
Notifications
You must be signed in to change notification settings - Fork 370
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
Reading from in_stream is extremely slow by default #774
Comments
Did you end up solving this in a halfway convenient way? @bitprophet any comment on the default behavior? |
Regarding the reason, comment in the code tells: # Take a nap so we're not chewing CPU.
time.sleep(self.input_sleep) |
How to set input_sleep to 0? A bit surprising one-liner with side-effectUse current context from invoke import task
@task
def check_config(c):
c.config.runners.local.input_sleep = 0
with open("docker-compose.yml", "rb") as in_stream:
# c.run("docker-compose -f docker-compose.yml config")
c.run("docker-compose -f - config", in_stream=in_stream) But be aware: this is changing class (not object) property - so the value holds true for any subsequent call of the Local runner. In case of from invoke import task
@task
def check_config(c):
c.config.runners.local.input_sleep = 0
with open("docker-compose.yml", "rb") as in_stream:
# c.run("docker-compose -f docker-compose.yml config")
c.run("docker-compose -f - config", in_stream=in_stream)
@task
def check_sleepy(c):
with open("docker-compose.yml", "rb") as in_stream:
# c.run("docker-compose -f docker-compose.yml config")
c.run("docker-compose -f - config", in_stream=in_stream) the timing will depend on order of task executions. Fast one: $ invoke check_config check_sleepy and slow one (as the check_sleepy uses default input_sleep) $ invoke check_sleepy check_config For this reason it seems safer to set this on module level, as it is least surprising: Less surprising methodfrom invoke.runners import Local
Local.input_sleep = 0 (this is the method @atleta has described) from invoke import task
from invoke.runners import Local
Local.input_sleep = 0
@task
def check_config(c):
# c.config.runners.local.input_sleep = 0
with open("docker-compose.yml", "rb") as in_stream:
# c.run("docker-compose -f docker-compose.yml config")
c.run("docker-compose -f - config", in_stream=in_stream)
@task
def check_sleepy(c):
with open("docker-compose.yml", "rb") as in_stream:
# c.run("docker-compose -f docker-compose.yml config")
c.run("docker-compose -f - config", in_stream=in_stream) |
It sounds like the right fix for this is to make the sleep only occur when But if one is replaying something via a custom input stream that's definitely not needed or, clearly, wanted! I'd accept a patch that does this (usual caveat that it needs tests, etc). |
Lines 59 to 60 in 267182b
If the purpose of the sleep is to “Take a nap so we're not chewing CPU.” should this sleep be conditional upon there not having been any data in the previous read? (So that we only sleep when waiting for more data, but if there is data, read all of it as fast as possible, and only have one "sleepless-read" each time we reach the end of the available data.) Also, 1000B buffer seems small – how about something like |
I have encountered this too. I managed to speed things up a lot by using I like @asqui's idea that this should only sleep when the buffer is empty. with (
mock.patch("time.sleep", new=lambda _: None),
mock.patch.object(ctx.runners.local, "read_chunk_size", new=io.DEFAULT_BUFFER_SIZE),
):
ctx.run(...) |
This change means that we don't delay reading the input stream when there is still data available to read from it. This provides a significant speed improvement to scripts which are passing a populated stream of data, rather than awaiting user input from stdin. See pyinvoke#774
This change means that we don't delay reading the input stream when there is still data available to read from it. This provides a significant speed improvement to scripts which are passing a populated stream of data, rather than awaiting user input from stdin. See pyinvoke#774
I've opened a PR which I hope will address this issue: #983 |
This change means that we don't delay reading the input stream when there is still data available to read from it. This provides a significant speed improvement to scripts which are passing a populated stream of data, rather than awaiting user input from stdin. See pyinvoke#774
This change means that we don't delay reading the input stream when there is still data available to read from it. This provides a significant speed improvement to scripts which are passing a populated stream of data, rather than awaiting user input from stdin. See pyinvoke#774
Nice, thanks for this change! Is it worth reframing the PR as "Speed up reading from in_stream" and also including the increase of |
No worries!
I'm happy to rename it -- I think that's a better name. Thank you.
In my case I didn't see any difference once the In applications with larger buffers I can imagine it making a difference though, so I'll include it anyway! EDIT: It does indeed make a minor difference in my case, though it's harder to notice because the |
@atleta (or anyone else): did you ever figure out how to work around this issue in a Fabric connection? EDIT: Answering my own question. After creating my Fabric connection ( conn.config.runners.remote.input_sleep = 0 |
I've run into this using fabric2, but it seems to be an invoke issue: run passes data from in_stream to the process in an extremely slow manner. About 90 CPS (yes, that is characters per second). So if I enable
echo_stdin
, it looks like a screen from your typical hacker movie (only without the chirp).Now while writing this bug report, I found a hint in the code (and then in the documentation) that this was intentional:
input_sleep
is set to 0.01 on invoke.Runner. But this seems like a pretty surprising default and, at least compared to the effect and the surprise factor, not a very well documented one. Also, probably my fault, but I did not find a way how to set it or disable it. After skimming the documentation, I have no idea which key to set.I've figured out how to set echo_stdin using the environment variables when running things from fabric, but the same scheme did not work out for input_sleep. Which means I wasn't able to guess the correct key. I've tried
runners.local.input_sleep
and `run.input_sleep. (So I ended up importing the class and then assigning 0 to the member but that's pretty lame.)Actually, what's the point of this at all? If the input is not ready, the read will block anyway. If it's ready, why slow things down?
The text was updated successfully, but these errors were encountered: