我正在使用非常标准的 Threading.Event:
主线程到达一个运行循环的点:
event.wait(60)
另一个阻塞请求,直到有可用答复为止,然后启动:
event.set()
我希望主线程选择 40 秒,但事实并非如此。
来自 Python 2.7 源 Lib/threading.py:
# 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)
我们得到的是每 500us 运行一次的选择系统调用。
这会导致机器上出现明显的负载,并且选择循环非常紧密。
有人可以解释一下为什么涉及平衡行为以及为什么它与等待文件描述符的线程不同。
其次,是否有更好的方法来实现一个大部分睡眠的主线程而不需要如此紧密的循环?
我最近遇到了同样的问题,我还追踪到了这个确切的代码块threading
module.
太糟糕了。
解决方案是使线程模块过载,或者迁移到python3
,这部分实现已得到修复。
就我而言,迁移到 python3 需要付出巨大的努力,所以我选择了前者。我所做的是:
- 我创建了一个快速
.so
文件(使用cython
)有一个接口pthread
。它包括调用相应的Python函数pthread_mutex_*
功能和链接libpthread
。具体来说,与我们感兴趣的任务最相关的函数是pthread_mutex_timedlock http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_mutex_timedlock.html.
- 我创建了一个新的
threading2
模块,(并替换所有import threading
我的代码库中的行import threading2
). In threading2
,我重新定义了所有相关的类threading
(Lock
, Condition
, Event
),还有来自Queue
我经常使用它(Queue
and PriorityQueue
). The Lock
类完全重新实现使用pthread_mutex_*
函数,但其余的要容易得多——我只是对原始函数进行了子类化(例如threading.Event
),并覆盖__init__
创造我的新Lock
类型。剩下的就工作了。
新政的实施Lock
类型与原始实现非常相似threading
,但我基于新的实现acquire
在我找到的代码上python3
's threading
模块(当然,它比上述“平衡行为”块简单得多)。这部分相当简单。
(顺便说一句,我的例子的结果是我的大规模多线程进程加速了 30%。甚至超出了我的预期。)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)