我使用非常标准的Threading.Event: 主线程在一个循环中运行:
event.wait(60)
请求中的其他阻止,直到回复可用,然后启动a:
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选择一次系统调用。 这会导致机器上出现明显的负载,选择循环非常紧张。
有人可以解释为什么涉及平衡行为,为什么它与等待文件描述符的线程不同。
第二,有没有更好的方法来实现一个大多数没有这么紧的循环的主线程?
答案 0 :(得分:3)
我最近遇到了同样的问题,我还在threading
模块中跟踪了这个确切的代码块。
太糟糕了。
解决方案是重载线程模块,或迁移到python3
,这部分实现已经修复。
在我的情况下,迁移到python3本来是一项巨大的努力,所以我选择了前者。我做的是:
.so
文件(使用cython
),其中包含pthread
的接口。它包括调用相应pthread_mutex_*
函数的python函数,以及针对libpthread
的链接。具体而言,与我们感兴趣的任务最相关的功能是pthread_mutex_timedlock。threading2
模块,(并用import threading
替换了我的代码库中的所有import threading2
行。在threading2
中,我重新定义了threading
(Lock
,Condition
,Event
)以及来自Queue
的所有相关类别我经常使用(Queue
和PriorityQueue
)。 Lock
类完全使用pthread_mutex_*
函数重新实现,但其余的更容易 - 我只是将原始子类(例如threading.Event
)子类化,并覆盖__init__
到创建我的新Lock
类型。其余的工作正常。新Lock
类型的实现与threading
中的原始实现非常相似,但我基于acquire
的新实现基于python3
中找到的代码} threading
模块(当然,它比上述“平衡行为”块简单得多)。这部分相当简单。
(顺便说一句,我的案例结果是我的大规模多线程进程加速了30%。甚至超出了我的预期。)
答案 1 :(得分:2)