python time sleep和wait_Python time.sleep()与event.wait()的比较

使用exit_flag.wait(timeout=DELAY)将更具响应性,因为当设置exit_flag时,您将立即脱离while循环。使用time.sleep,即使在设置了事件之后,您也要在time.sleep调用中等待,直到您睡眠了DELAY秒。

在实现方面,Python2.x和Python3.x有非常不同的行为。在Python 2.x中,Event.wait是用纯Python实现的,它使用了一堆小的time.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)

这实际上意味着使用wait可能比无条件地睡满DELAY需要更多的CPU,但它的好处是(可能很多,取决于DELAY有多长时间)更具响应性。这也意味着需要频繁地重新获取GIL,以便可以安排下一个睡眠,而time.sleep可以释放GIL以进行完整的DELAY。现在,更频繁地获取GIL是否会对应用程序中的其他线程产生明显的影响?也许是,也许不是。这取决于有多少其他线程正在运行以及它们有什么样的工作负载。我的猜测是,除非有大量的线程,或者另一个线程执行大量的CPU绑定工作,否则它不会特别明显,但它很容易尝试两种方法并看到。

在Python3.x中,大部分实现都转移到纯C代码:import _thread # C-module

_allocate_lock = _thread.allocate_lock

class 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 code

else:

gotit = waiter.acquire(False)

return gotit

finally:

self._acquire_restore(saved_state)

if not gotit:

try:

self._waiters.remove(waiter)

except ValueError:

pass

class 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代码:/* Helper to acquire an interruptible lock with a timeout. If the lock acquire

* is interrupted, signal handlers are run, and if they raise an exception,

* PY_LOCK_INTR is returned. Otherwise, PY_LOCK_ACQUIRED or PY_LOCK_FAILURE

* are returned, depending on whether the lock can be acquired withing the

* timeout.

*/

static PyLockStatus

acquire_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 {

/* first a simple non-blocking try without releasing the GIL */

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) {

/* Run signal handlers if we were interrupted. Propagate

* exceptions from signal handlers, such as KeyboardInterrupt, by

* passing up PY_LOCK_INTR. */

if (Py_MakePendingCalls() < 0) {

return PY_LOCK_INTR;

}

/* If we're using a timeout, recompute the timeout after processing

* signals, since those can take time. */

if (microseconds > 0) {

_PyTime_gettimeofday(&curtime);

microseconds = ((endtime.tv_sec - curtime.tv_sec) * 1000000 +

(endtime.tv_usec - curtime.tv_usec));

/* Check for negative values, since those mean block forever.

*/

if (microseconds <= 0) {

r = PY_LOCK_FAILURE;

}

}

}

} while (r == PY_LOCK_INTR); /* Retry if we were interrupted. */

return r;

}

这个实现是响应性的,不需要频繁的唤醒来重新获取GIL,所以您可以同时获得这两个世界的最佳结果。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值