我有一个主流程正在吃来自许多不同市场的数据。它对消息进行一些初步处理,然后将其传递到多处理队列(每个独特的市场都有自己的专用进程,在队列的另一端称为Parse
)。然后主要流程为所涉及的特定市场调用mp.Event.set()
。
在Parse
内是对mp.Event.wait()
的调用,除非有数据被送入队列,否则会暂停进程。在Parse
结束时,它调用mp.Event.clear().
我这样做是因为我使用while True
循环来捕获数据到队列的那一刻。如果我不暂停Parse
,它将使用100%的CPU并且我没有足够的内核(更不用说它非常浪费了)。
今天晚上,我意识到Parse
花了很长时间才能跑,从.3秒到18秒。市场数据消息可以每12毫秒发出一次,所以显然这是不可行的。除Parse
外,mp.Event.wait()
的每个方面都非常快。此调用几乎占运行时间的100%。
我将所有mp.Event
个对象存储在配置文件中定义的字典中。我担心发生两件事之一:
设置和清除事件的每个实例都会阻塞所有其他事件,其方式类似于mp.Manager
如何处理共享对象。
mp.Event
速度很慢,其状态需要很长时间才能跨进程传播......
我正在考虑通过使用zmq
(ZeroMQ)而不是mp.Queue
来管理数据来解决这个问题,但在我设置之前,我想问聪明的人。
我在做一些明显错误的事吗?有没有办法加快mp.Event
标记?
修改
在回应评论时,这是一个例子:
在config.py
文件中,我像这样定义字典:
E,Q={},{}
for m in all_markets:
E[m] = mp.Event()
Q[m] = mp.Queue()
然后在读取数据的主进程中,我调用sort
,看起来像这样:
def sort(message, m):
if message satisfies condition1:
define some args
Q[m].put(message, *args)
E[m].set()
if message satisfies condition2:
#basically the same
然后最后在Parse
,这是在程序启动时启动的:
def Parse(message,m,Q,E):
while True:
E[m].wait()
message = Q[m].get()
#do a bunch of processing on the message
#put the results in some other queues
E[m].clear()
EDIT2
生成过程并像这样开始:
def mitosis():
mp.Process(target=main).start()
def pstart(m,func,**kwargs):
if func=='parser':
p = mp.Process(target=parser, args=(m, Q, E, *args) )
p.start()
def main():
PROCS={}
for m in all_markets:
for procs in proclist:
PROCS[(m,proc)] = pstart(m,proc,**kwargs)
答案 0 :(得分:2)
我认为您的问题是您的Event
代码已损坏。
想象一下这种情况:
sort
调用m
。sort
来电Q[m].put
和E[m].set
。Parse
醒来,Q[m].get
,然后开始处理。sort
调用m
。sort
来电Q[m].put
和E[m].set
。Parse
完成处理第一条消息,调用E[m].clear
。现在Parse
正在等待再次设置Event
。这可能不会发生很长一段时间。并且,即使它很快发生,它仍然不会赶上;它只为每个Q[m].get
执行一次Event.wait
。
所以,你最终得到的是Parse
看起来越来越远。当你试图对其进行分析以找出原因时,你会看到它花费所有时间等待E[m].wait
。但这不是因为E[m].wait
很慢,而是因为事件触发器丢失了。
这不是唯一的竞争条件,它只是最明显的竞争条件。
一般问题是您不能以这种方式使用事件对象。通常情况下,您可以使用Condition
替代,或一次性触发和自动重置Event
来解决此问题,并在每个Q[m].get(block=False)
后循环Event
。
但实际上,首先没有必要这样做。如果你只是完全移除Event
,那么当Parse
调用Q[m].get
时,会阻塞,直到那里有东西为止。因此,当sort
调用Q[m].put
时,会唤醒Parse
,并且没有其他任何需要。
事实上,Queue
的重点在于它本身就是自我同步的。如果您不想这样做,请使用Pipe
,然后您可以使用Condition
进行信令。但在简单的情况下,这只是Queue
的效率较低的版本。