Closed eplodn closed 6 years ago
Thank you for your report.
This actually doesn't have anything to do with timers. What's going on is that Cmd
(and thus MyShell
) is making a blocking operating system call via input
and preventing the gevent event loop from running at all. To put it another way, it's not cooperative and no other greenlets can run while it is blocking. You can see this in the traceback if you hit Ctrl-C while the program is sitting there:
File "/tmp/test.py", line 33, in cmdloop
cmd.Cmd.cmdloop(self)
File "//3.6/lib/python3.6/cmd.py", line 126, in cmdloop
line = input(self.prompt)
The solution to make it cooperative is two-fold: pass cooperative versions of stdin
and stdout
and ask it not to use the input
function:
# Create cooperative versions for this object
from gevent.fileobject import FileObjectThread
stdin = FileObjectThread(sys.stdin)
stdout = FileObjectThread(sys.stdout)
shell = MyShell(stdin=stdin, stdout=stdout)
# Make it use those instead of `input`
shell.use_rawinput = 0
# Now this will cooperate with the event loop
shell.cmdloop()
(Using a custom stdin/out is documented here for Cmd
, and the fact that sys.std[in|out]
is not patched by patch_all
on Python 3---hence the need to pass specific objects---is documented here.)
Thanks a ton @jamadden!
Any idea how can I use gnureadline
completer if I'm not using raw input
but rather wrapping the stdin
with FileObjectThread
? gnureadline
is not happy if sys.stdin
!= sys.__stdin__
.
Sorry, no idea.
Description:
I am writing a simple command interpreter with a timer to kill the interpreter if not used for some time. However, because of the usage of gevent monkey patching, the timer no longer fires.
Attached is the minimal example demonstrating this.
If the
gevent.monkey.patch_thread()
line is commented out, the Timer will fire in 1 second, and the line 'Foo!' will be printed. If thegevent.monkey.patch_thread()
line is enabled, the Timer will never fire.What I've run: