Python time.sleep()与event.wait()

Python time.sleep()与event.wait(),第1张

Python time.sleep()与event.wait()

使用

exit_flag.wait(timeout=DELAY)
将具有更高的响应速度,因为在
exit_flag
设置时,您将立即退出while循环。使用
time.sleep
,即使在设置了事件之后,您也将在
time.sleep
通话中等待直到睡了
DELAY
几秒钟。

在实现方面,Python 2.x和Python 3.x具有非常不同的行为。在Python
2.x

Event.wait
中,使用大量的小
time.sleep
调用在纯Python中实现:

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)

实际上,这意味着使用

wait
它可能比仅
DELAY
无条件地休眠整个计算机要消耗更多的CPU
,但这样做的好处是(
DELAY
响应时间长很多,取决于时间长短)。这也意味着需要经常重新获取GIL,以便可以安排下一次睡眠,同时
time.sleep
可以完全释放GIL
DELAY
。现在,更频繁地获取GIL是否会对您应用程序中的其他线程产生明显影响?也许不是。这取决于正在运行的其他线程数以及它们承担的工作量。我的猜测是,除非您有大量线程,或者另一个线程正在执行大量CPU限制工作,否则它不会特别引人注目,但是它很容易同时尝试和观察。

在Python 3.x中,大部分实现都移至纯C代码:

import _thread # C-module_allocate_lock = _thread.allocate_lockclass Condition:    ...    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()        gotit = False        try:    # restore state no matter what (e.g., KeyboardInterrupt) if timeout is None:     waiter.acquire()     gotit = True else:     if timeout > 0:         gotit = waiter.acquire(True, timeout)  # This calls C pre     else:         gotit = waiter.acquire(False) return gotit        finally: self._acquire_restore(saved_state) if not gotit:     try:         self._waiters.remove(waiter)     except ValueError:         passclass Event:    def __init__(self):        self._cond = Condition(Lock())        self._flag = False    def wait(self, timeout=None):        self._cond.acquire()        try: signaled = self._flag if not signaled:     signaled = self._cond.wait(timeout) return signaled        finally: self._cond.release()

和获得锁的C代码:

static PyLockStatusacquire_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds){    PyLockStatus r;    _PyTime_timeval curtime;    _PyTime_timeval endtime;    if (microseconds > 0) {        _PyTime_gettimeofday(&endtime);        endtime.tv_sec += microseconds / (1000 * 1000);        endtime.tv_usec += microseconds % (1000 * 1000);    }    do {                r = PyThread_acquire_lock_timed(lock, 0, 0);        if (r == PY_LOCK_FAILURE && microseconds != 0) { Py_BEGIN_ALLOW_THREADS  // GIL is released here r = PyThread_acquire_lock_timed(lock, microseconds, 1); Py_END_ALLOW_THREADS        }        if (r == PY_LOCK_INTR) {  if (Py_MakePendingCalls() < 0) {     return PY_LOCK_INTR; }  if (microseconds > 0) {     _PyTime_gettimeofday(&curtime);     microseconds = ((endtime.tv_sec - curtime.tv_sec) * 1000000 +          (endtime.tv_usec - curtime.tv_usec));          if (microseconds <= 0) {         r = PY_LOCK_FAILURE;     } }        }    } while (r == PY_LOCK_INTR);      return r;}

该实现是响应式的,不需要频繁唤醒就可以重新获取GIL,因此您可以两全其美。



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5644481.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存