Jon*_*Rom 7 python events multithreading busy-loop
我正在使用非常标准的Threading.Event:主线程在一个循环中运行:
event.wait(60)
Run Code Online (Sandbox Code Playgroud)
其他阻止请求,直到回复可用,然后启动:
event.set()
Run Code Online (Sandbox Code Playgroud)
我希望主线程选择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)
Run Code Online (Sandbox Code Playgroud)
我们得到的是每500us选择一次系统调用.这会导致机器上出现明显的负载,并且选择循环非常紧凑.
有人可以解释为什么涉及平衡行为,为什么它与等待文件描述符的线程不同.
第二,有没有更好的方法来实现一个大多数睡眠主线程没有这么紧的循环?
我最近遇到了同样的问题,我也追踪到了模块中的这个确切的代码块threading。
太糟糕了。
解决方案是要么重载线程模块,要么迁移到python3,其中这部分实现已得到修复。
就我而言,迁移到 python3 需要付出巨大的努力,所以我选择了前者。我所做的是:
.so带有. 它包括调用相应函数的 python 函数,并链接到. 具体来说,与我们感兴趣的任务最相关的函数是pthread_mutex_timedlock。cythonpthreadpthread_mutex_*libpthreadthreading2模块(并将import threading代码库中的所有行替换为import threading2)。在 中threading2,我重新定义了threading( Lock, Condition, Event) 中的所有相关类,以及Queue我经常使用的类 (Queue和PriorityQueue)。该类Lock完全使用函数重新实现pthread_mutex_*,但其余的则容易得多——我只是对原始类进行子类化(例如threading.Event),并重写__init__以创建我的新Lock类型。剩下的就工作了。新Lock类型的实现与 中的原始实现非常相似threading,但我的新实现基于我在的模块acquire中找到的代码(当然,它比上述“平衡行为”块简单得多)。这部分相当简单。python3threading
(顺便说一句,我的例子的结果是我的大规模多线程进程加速了 30%。甚至超出了我的预期。)