Python 当gevent微线程处于while循环中时,如何停止它?

Python 当gevent微线程处于while循环中时,如何停止它?,python,while-loop,timeout,gevent,Python,While Loop,Timeout,Gevent,我有一个问题,情况就像下面的代码。目标函数(wait)处于while循环中或花费了大量时间,因此我想杀死微线程。如何杀死线1 注意:用户的微线程可能是CPU限制的操作(例如,没有任何IO操作的while循环) gevent.killall()和thread.kill()都需要运行线程调度程序,它们不会像我们预期的那样终止线程。您在那里做了很多不必要的工作。您只需将秒数作为关键字参数传递给以下对象: >>> import gevent >>> def wait(

我有一个问题,情况就像下面的代码。目标函数(wait)处于while循环中或花费了大量时间,因此我想杀死微线程。如何杀死线1

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


gevent.killall()
thread.kill()
都需要运行
线程调度程序,它们不会像我们预期的那样终止线程。

您在那里做了很多不必要的工作。您只需将秒数作为关键字参数传递给以下对象:

>>> 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秒后杀死正在运行的greenlet
wait()
。您无法捕获
超时
,因为它将为您捕获超时,并且只要超时是它例外的超时,就可以无声地杀死greenlet。以下是的源代码中的一个片段

你也可以用它杀死一只小绿猫。我认为这是一个错误的方法,但我还是要添加一个例子。以下操作将运行greenlet 5秒,然后将其杀死:

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

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

from gevent.monkey import patch_all
patch_all()

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

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

在CPU受限的情况下,Gevent的开关和超时将不起作用

我们不能假设用户写的代码是正确的,因为没有死环,死环的操作是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')
最后,我使用“信号”API来解决这个问题

请参阅

关于Gevent的开关和超时:

以下代码可能供您参考

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.killall()!gevent.killall()将无法按预期工作,我在问题中添加了一些说明。谢谢你的评论。对不起,我没说清楚。我的意思是像一个while循环,但是你没有机会添加gevent.sleep(1)来让这个greenlet睡眠。就像调用第三方库函数一样,它很长一段时间没有响应。@user3611389我认为,如果net无法进行上下文切换,您不可能通过超时greenlet来解决长阻塞问题。谢谢您的回答,正如您所说,我们没有更改gevent的超时或终止微线程,因为我们没有机会执行上下文切换,我们必须运行非协作线程或使用系统计时器API。这个答案有助于解释问题中的代码不起作用的原因,谢谢。谢谢你的回答,但是在CPU受限的情况下,交换机没有机会运行。这个答案解决不了问题,无论如何,谢谢。过一会儿我会更详细地描述我的问题。
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))