Python中的abortable sleep()

2024-06-01 03:56:30 发布

您现在位置:Python中文网/ 问答频道 /正文

我需要一个可以中止的sleep()方法(如herehere)的方法。在

我的方法是让threading.Event.wait()在指定的持续时间内超时:

def abortable_sleep(secs, abort_event):
    abort_event.wait(timeout=secs)
    abort_event.clear()

在调用abortable_sleep(10, _abort)之后,我现在可以(从另一个线程)调用_event.set(_abort),让{}在10秒之前终止。在

示例:

^{pr2}$

输出:

0.000001 thread started
3.002668 thread stopped
0.000002 thread started
3.003014 thread stopped
0.000001 thread started
3.002928 thread stopped
0.000001 thread started

此代码按预期工作,但我仍有一些问题:

  • 有没有一种更容易的方法来获得s.th。比如sleep()哪一个可以中止?在
  • 你能做得更好吗?E、 g.这样我必须小心Event实例,它没有绑定到abortable_sleep()的实例
  • 在高频循环中,如while True: abortable_sleep(0.0001),我是否必须预料到性能问题?wait()-timeout是如何实现的?在

Tags: 实例方法eventheretimeoutsleepthreadthreading
3条回答

我有一个包装类,它基本上在Event上添加一些睡眠语义。好在你只需要传递一个Sleep对象,如果你愿意,你可以多次调用sleep()(尽管sleep()不是线程安全的),你可以从另一个线程wake()。在

from threading import Event

class Sleep(object):
    def __init__(self, seconds, immediate=True):
        self.seconds = seconds
        self.event = Event()
        if immediate:
            self.sleep()

    def sleep(self, seconds=None):
        if seconds is None:
            seconds = self.seconds
        self.event.clear()
        self.event.wait(timeout=seconds)

    def wake(self):
        self.event.set()

使用示例:

^{pr2}$

上面的结果可能是这样的:

1423750549 - sleep
1423750552 - awake
1423750552 - sleeping again
1423750553 - wakeup!
1423750553 - awake again

完全是你所做的,只是封装在一个类中。在

由于比赛条件,您的解决方案并不总是完全正确的。您应该改用^{}。创建后立即调用aquire()。当你想睡觉时,调用acquire()并超时,如果acquire()返回true,则调用release()。要提前中止睡眠,请从另一个线程调用release();如果没有正在进行的睡眠,这将引发ValueError。在

如果另一个线程在错误的时间调用set(),那么使用一个事件是有问题的(即在您实际等待事件之外的任何时间)。在

我会把sleep/abort函数打包到一个新的类中:

class AbortableSleep():
    def __init__(self):
        self._condition = threading.Condition()

    def __call__(self, secs):
        with self._condition:
            self._aborted = False
            self._condition.wait(timeout=secs)
            return not self._aborted

    def abort(self):
        with self._condition:
            self._condition.notify()
            self._aborted = True

然后我还将提供一个Thread子类来管理每个线程的唤醒例程的共享:

^{pr2}$

任何其他可以访问此线程的线程都可以调用wakeup()来中止当前的abortable_sleep()(如果有一个正在进行)。在


使用ThreadWithWakeup

可以使用ThreadWithWakeup类创建线程,并按如下方式使用:

class MyThread(ThreadWithWakeup):
    def run(self):
        print "Sleeper: sleeping for 10"
        if self.abortable_sleep(10):
            print "Sleeper: awoke naturally"
        else:
            print "Sleeper: rudely awoken"

t = MyThread()
t.start()
print "Main: sleeping for 5"
for i in range(5):
    time.sleep(1)
    print i + 1 
print "Main: waking thread"
t.wakeup()

其输出如下:

Sleeper: sleeping for 10
Main: sleeping for 5
1
2
3
4
5
Main: waking thread
Sleeper: rudely awoken

单独使用AbortableSleep

您也可以单独使用AbortableSleep类,如果出于某种原因不能使用ThreadWithWakeup类(可能您在主线程中,可能有其他东西为您创建线程,等等),这很方便:

abortable_sleep = AbortableSleep()
def run():
    print "Sleeper: sleeping for 10"
    if abortable_sleep(10):
        print "Sleeper: awoke naturally"
    else:
        print "Sleeper: rudely awoken"
threading.Thread(target=run).start()

print "Main: sleeping for 5"
for i in range(5):
    time.sleep(1)
    print i + 1
print "Main: aborting"
abortable_sleep.abort()

相关问题 更多 >