如何在while循环中停止gevent微线程?

时间:2014-05-07 09:08:51

标签: python while-loop timeout gevent

我遇到了问题,情况就像下面的代码一样。目标函数(等待)是在一个while循环或花了很长时间,所以我想杀死微线程。如何杀死thread1?

注意:用户的微线程可能是CPU绑定操作(例如没有任何IO操作的while循环。)

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()都要求thread scheduler运行,它们不会像我们预期的那样终止线程。

3 个答案:

答案 0 :(得分:0)

你在那里做了很多不必要的工作。您可以简单地将秒作为关键字参数传递给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()的greenlet。你无法抓住Timeout,因为join()会抓住它,只要超时就是那个,就会默默地杀死greenlet除外。以下是来自join()

来源的greenlet.py摘录
try:
    t = Timeout.start_new(timeout)
    ... SNIP ...
except Timeout as ex:
    self.unlink(switch)
    if ex is not t:
        raise

您也可以使用kill()杀死greenlet。我认为这是错误的方法,但无论如何我都会添加这个例子。以下将运行greenlet 5秒然后杀死它:

>>> g = gevent.spawn(wait)
>>> with gevent.Timeout(5, False):
...     g.join()
... g.kill()
...

答案 1 :(得分:0)

只有“等待”微线程有机会切换时,您的代码才有效。如果你控制线程的代码,你可以通过调用gevent.sleep来实现。否则,如果您的线程代码是在python中实现并使用IO操作,您可以尝试通过以下方式修补python函数:

from gevent.monkey import patch_all
patch_all()

这将允许您的线程在遇到各种IO操作时切换。

答案 2 :(得分:-2)

我遇到同样的问题,我必须杀死一个greenlet线程(它有用户编写的代码)。

在CPU绑定操作的情况下,Gevent的开关和超时将无效!

我们不能假设用户编写了没有死循环且具有CPU绑定操作的正确代码。

最后,我使用“Signal”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))