如何在while循环中停止gevent微线程?
我遇到了一个问题,情况就像下面的代码一样。目标函数(wait)在一个循环里运行,或者花了很长时间,所以我想结束这个微线程。请问怎么才能结束线程1呢?
注意:用户的微线程可能是一个占用CPU的操作(比如一个没有任何输入输出操作的循环)。
import gevent
from gevent import Timeout
def wait():
while(1):
pass
print 'end'
timer = Timeout(1).start()
thread1 = gevent.spawn(wait)
try:
thread1.join(timeout=timer)
except Timeout:
print('Thread 1 timed out')
无论是 gevent.killall()
还是 thread.kill()
都需要 线程调度器
来运行,它们并不会像我们预期的那样结束线程。
3 个回答
我遇到了同样的问题,我需要终止一个用户编写代码的绿色线程(greenlet)。
如果是CPU密集型操作,Gevent的切换和超时功能将无法正常工作!
我们不能假设用户写的代码是正确的,里面没有死循环或者CPU密集型的操作。
最后,我使用了“信号”API来解决这个问题。
请参考 https://docs.python.org/2/library/signal.html
关于Gevent的切换和超时功能,可以查看这个链接: https://groups.google.com/forum/#!topic/gevent/eBj9YQYGBbc
下面的代码可能对你有帮助。
from gevent.monkey import patch_all;patch_all()
import gevent
import time
def fucking_loop():
while True:
pass
def fucking_loop_with_timeout():
with gevent.Timeout(10):
while True:
pass
def fail_to_kill():
deadline = time.time() + 10
thread = gevent.spawn(fucking_loop)
while deadline > time.time():
# gevent.sleep will switch out of main thread
gevent.sleep(1)
# This line of code will never been executed
# because gevent will not switch to main thread.
thread.kill()
def fail_to_kill_2():
thread = gevent.spawn(fucking_loop)
# Will never timeout because of the same reason
fucking_loop_with_timeout()
# This line of code will never been executed
# because gevent will not switch to main thread.
thread.join(timeout=10)
thread.kill()
def kill_fucking_loop_works():
import signal
timeout = 10
thread = gevent.spawn(fucking_loop)
def kill_thread(*args, **kwargs):
if not thread.dead:
thread.kill(timeout=1)
signal.signal(signal.SIGALRM, kill_thread)
signal.alarm(int(timeout))
你的代码只有在“等待”的微线程有机会切换时才能正常工作。如果你能控制你的线程代码,可以通过调用 gevent.sleep 来实现这个切换。否则,如果你的线程代码是用 Python 写的,并且使用了输入输出操作,你可以尝试通过以下方式来修改 Python 的函数:
from gevent.monkey import patch_all
patch_all()
这样可以让你的线程在遇到不同的输入输出操作时进行切换。
你在这里做了很多不必要的工作。其实你可以直接把秒数作为关键字参数传给 join()
,像下面这样:
>>> import gevent
>>> def wait():
... while True:
... print("In loop")
... gevent.sleep(1) # To not fill the screen..
...
>>>
>>> g = gevent.spawn(wait)
>>> g.join(timeout=5)
下面的代码会在5秒后终止正在运行 wait()
的绿色线程。你 无法 捕捉到 Timeout
,因为 join()
会为你处理这个问题,并在超时的情况下默默地终止绿色线程。以下是来自 greenlet.py
的 join()
的一段代码:
try:
t = Timeout.start_new(timeout)
... SNIP ...
except Timeout as ex:
self.unlink(switch)
if ex is not t:
raise
你也可以使用 kill()
来终止一个绿色线程。我认为这种方法不太对,但我还是会给出例子。下面的代码会运行绿色线程5秒,然后将其终止:
>>> g = gevent.spawn(wait)
>>> with gevent.Timeout(5, False):
... g.join()
... g.kill()
...