Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python time.sleep()与event.wait()的比较_Python_Multithreading_Sleep - Fatal编程技术网

Python time.sleep()与event.wait()的比较

Python time.sleep()与event.wait()的比较,python,multithreading,sleep,Python,Multithreading,Sleep,我想在我的多线程Python应用程序中定期执行一个操作。我见过两种不同的方法 exit = False def thread_func(): while not exit: action() time.sleep(DELAY) 或 一种方式比另一种方式有优势吗?是使用更少的资源,还是更好地使用其他线程和GIL?哪一个使我的应用程序中的其余线程更具响应性 (假设一些外部事件集exit或exit\u flag,并且我愿意在关闭时等待完全延迟)使用exit\u

我想在我的多线程Python应用程序中定期执行一个操作。我见过两种不同的方法

exit = False
def thread_func(): 
    while not exit:
       action()
       time.sleep(DELAY)

一种方式比另一种方式有优势吗?是使用更少的资源,还是更好地使用其他线程和GIL?哪一个使我的应用程序中的其余线程更具响应性

(假设一些外部事件集
exit
exit\u flag
,并且我愿意在关闭时等待完全延迟)

使用
exit\u flag。wait(timeout=delay)
将更具响应性,因为当设置
exit\u flag
时,您将立即中断while循环。使用
time.sleep
,即使在设置了事件之后,您也要在
time.sleep
中等待,直到您睡眠
延迟

在实现方面,Python2.x和Python3.x有非常不同的行为。在Python2.x中,Event.wait是在纯Python中使用一系列小的
时间来实现的。sleep
调用:

from time import time as _time, sleep as _sleep

....
# This is inside the Condition class (Event.wait calls Condition.wait).
def wait(self, timeout=None):
    if not self._is_owned():
        raise RuntimeError("cannot wait on un-acquired lock")
    waiter = _allocate_lock()
    waiter.acquire()
    self.__waiters.append(waiter)
    saved_state = self._release_save()
    try:    # restore state no matter what (e.g., KeyboardInterrupt)
        if timeout is None:
            waiter.acquire()
            if __debug__:
                self._note("%s.wait(): got it", self)
        else:
            # Balancing act:  We can't afford a pure busy loop, so we
            # have to sleep; but if we sleep the whole timeout time,
            # we'll be unresponsive.  The scheme here sleeps very
            # little at first, longer as time goes on, but never longer
            # than 20 times per second (or the timeout time remaining).
            endtime = _time() + timeout
            delay = 0.0005 # 500 us -> initial delay of 1 ms
            while True:
                gotit = waiter.acquire(0)
                if gotit:
                    break
                remaining = endtime - _time()
                if remaining <= 0:
                    break
                delay = min(delay * 2, remaining, .05)
                _sleep(delay)
            if not gotit:
                if __debug__:
                    self._note("%s.wait(%s): timed out", self, timeout)
                try:
                    self.__waiters.remove(waiter)
                except ValueError:
                    pass
            else:
                if __debug__:
                    self._note("%s.wait(%s): got it", self, timeout)
    finally:
        self._acquire_restore(saved_state)
以及获取锁的C代码:

/*Helper获取带有超时的可中断锁。如果锁获得
*被中断,信号处理程序运行,如果它们引发异常,
*返回PY_LOCK_INTR。否则,将获取PY_LOCK_或PY_LOCK_失败
*返回,具体取决于是否可以使用
*超时。
*/
静态Pylock状态
获取超时(PY线程类型锁定,PY超时微秒)
{
派洛克状态;
_PyTime_timeval curtime;
_PyTime_timeval endtime;
如果(微秒>0){
_PyTime_gettimeofday(&endtime);
endtime.tv_sec+=微秒/(1000*1000);
endtime.tv_usec+=微秒%(1000*1000);
}
做{
/*首先,在不释放GIL的情况下进行简单的非阻塞尝试*/
r=PyThread\u acquire\u lock\u timed(锁,0,0);
如果(r==PY\u锁定\u故障&&微秒!=0){
Py\u BEGIN\u ALLOW\u THREADS//GIL在这里发布
r=PyThread\u acquire\u lock\u timed(锁,微秒,1);
Py\u端头\u允许\u螺纹
}
如果(r==PY\u LOCK\u INTR){
/*如果我们被中断,请运行信号处理程序。传播
*信号处理程序的异常,如键盘中断
*放弃PY_LOCK_INTR*/
if(Py_MakePendingCalls()<0){
返回PY_LOCK_INTR;
}
/*如果使用超时,请在处理后重新计算超时
*信号,因为这需要时间*/
如果(微秒>0){
_PyTime_gettimeofday(&curtime);
微秒=((endtime.tv_秒-curtime.tv_秒)*1000000+
(endtime.tv_usec-curtime.tv_usec));
/*检查负值,因为这些值意味着永远阻塞。
*/
如果(微秒python2.*
正如@dano所说,event.wait更具响应性,
但是当系统在等待时将时间向后更改时,它可能是危险的

请参见此示例:

def someHandler():
   while not exit_flag.wait(timeout=0.100):
       action()
通常在100ms intrvall中调用
action()

但是当你改变时间,比如一小时,那么两个动作之间会有一个小时的停顿


结论:当允许更改时间时,应避免
event.wait

值得注意的是,event.wait()方法可以单独调用:

from threading import Event # Needed for the  wait() method
from time import sleep     

print("\n Live long and prosper!")
sleep(1)               # Conventional sleep() Method.
print("\n Just let that soak in..")   
Event().wait(3.0) # wait() Method, useable sans thread.
print("\n Make it So! = )\n")

那么,为什么不在多线程之外使用wait()作为sleep()的替代方法呢?简言之,Zen.(当然)代码的清晰性是很重要的。

设置
exit
标志的代码在哪里?是否在
action()中
调用,或者在另一个线程中调用,或者可能被信号处理程序调用?我使用
事件。在这种情况下,等待
,即使python 2.x在后台轮询。比如说,每隔1秒睡眠是合理的响应,干扰性较小。首先,第一次睡眠会浪费一些CPU时间。中断Event.wa的副作用我正在反向工程一个应用程序的python API,该应用程序有一个嵌入式python 2.5解释器(ableton live),并且父进程在某种程度上不喜欢python线程,可能它只是在处理事件时运行,这使得我注入的rconsole不负责任。如果我在time.sleep上循环,它仍然没有响应,但是如果我在主线程中使用event.wait并超时,父应用程序仍然在响应,而rconsole也有合理的响应。因此,这是否意味着
sleep(DELAY)
没有GIL那么重?尽管没有那么准确?@user3012759我想是的,因为在
wait
中每次醒来都需要重新获取GIL,而
sleep
可以在整个
DELAY
中释放GIL。这是python 2.x(在3.x中更好)特别是当线程数增加时,情况就更糟了。@tdelaney 3.x impl看起来怎么样?@tdelaney是的,很好。在Python 3.x中,等待是用C实现的,并在整个等待过程中释放GIL。我将更新我的答案以显示代码
def someHandler():
   while not exit_flag.wait(timeout=0.100):
       action()
from threading import Event # Needed for the  wait() method
from time import sleep     

print("\n Live long and prosper!")
sleep(1)               # Conventional sleep() Method.
print("\n Just let that soak in..")   
Event().wait(3.0) # wait() Method, useable sans thread.
print("\n Make it So! = )\n")