通过队列在两个进程之间交换对象(数据帧)时遇到了一些麻烦。
第一个进程从队列中获取数据,然后将数据放入队列中。 put-process更快,因此get-process应该通过读取所有对象来清除队列。
我有一些奇怪的行为,因为我的代码完美且按预期工作,但只有数据帧中的100行,对于1000行,get-process总是只占用一个对象。
import multiprocessing, time, sys
import pandas as pd
NR_ROWS = 1000
i = 0
def getDf():
global i, NR_ROWS
myheader = ["name", "test2", "test3"]
myrow1 = [ i, i+400, i+250]
df = pd.DataFrame([myrow1]*NR_ROWS, columns = myheader)
i = i+1
return df
def f_put(q):
print "f_put start"
while(1):
data = getDf()
q.put(data)
print "P:", data["name"].iloc[0]
sys.stdout.flush()
time.sleep(1.55)
def f_get(q):
print "f_get start"
while(1):
data = pd.DataFrame()
while not q.empty():
data = q.get()
print "get"
if not data.empty:
print "G:", data["name"].iloc[0]
else:
print "nothing new"
time.sleep(5.9)
if __name__ == "__main__":
q = multiprocessing.Queue()
p = multiprocessing.Process(target=f_put, args=(q,))
p.start()
while(1):
f_get(q)
p.join()
输出100rows数据帧,get-process获取所有对象
f_get start
nothing new
f_put start
P: 0 # put 1.object into the queue
P: 1 # put 2.object into the queue
P: 2 # put 3.object into the queue
P: 3 # put 4.object into the queue
get # get-process takes all 4 objects from the queue
get
get
get
G: 3
P: 4
P: 5
P: 6
get
get
get
G: 6
P: 7
P: 8
1000rows数据帧的输出,get-process只接受一个对象。
f_get start
nothing new
f_put start
P: 0 # put 1.object into the queue
P: 1 # put 2.object into the queue
P: 2 # put 3.object into the queue
P: 3 # put 4.object into the queue
get <-- #!!! get-process takes ONLY 1 object from the queue!!!
G: 1
P: 4
P: 5
P: 6
get
G: 2
P: 7
P: 8
P: 9
P: 10
get
G: 3
P: 11
知道我做错了什么,以及如何通过更大的数据帧?
答案 0 :(得分:4)
冒着不能完全提供功能完整的例子,这就是出了什么问题。
首先,它是一个时间问题。
我使用较大的DataFrame(10000
甚至100000
)再次尝试使用您的代码,我开始看到与您相同的事情。这意味着只要数组的大小超过某个阈值(系统(CPU?)),就会看到此行为。
我稍微修改了你的代码,以便更容易看到会发生什么。首先,5 DataFrames
put
进入队列而没有任何自定义time.sleep
。在f_get
函数中,我向循环(time.sleep(0)
)添加了一个计数器(以及while not q.empty()
,见下文)。
新代码:
import multiprocessing, time, sys
import pandas as pd
NR_ROWS = 10000
i = 0
def getDf():
global i, NR_ROWS
myheader = ["name", "test2", "test3"]
myrow1 = [ i, i+400, i+250]
df = pd.DataFrame([myrow1]*NR_ROWS, columns = myheader)
i = i+1
return df
def f_put(q):
print "f_put start"
j = 0
while(j < 5):
data = getDf()
q.put(data)
print "P:", data["name"].iloc[0]
sys.stdout.flush()
j += 1
def f_get(q):
print "f_get start"
while(1):
data = pd.DataFrame()
loop = 0
while not q.empty():
data = q.get()
print "get (loop: %s)" %loop
time.sleep(0)
loop += 1
time.sleep(1.)
if __name__ == "__main__":
q = multiprocessing.Queue()
p = multiprocessing.Process(target=f_put, args=(q,))
p.start()
while(1):
f_get(q)
p.join()
现在,如果你针对不同的行数运行它,你会看到如下内容:
<强> N = 100:强>
f_get start
f_put start
P: 0
P: 1
P: 2
P: 3
P: 4
get (loop: 0)
get (loop: 1)
get (loop: 2)
get (loop: 3)
get (loop: 4)
<强> N = 10000:强>
f_get start
f_put start
P: 0
P: 1
P: 2
P: 3
P: 4
get (loop: 0)
get (loop: 1)
get (loop: 0)
get (loop: 0)
get (loop: 0)
这告诉我们什么?
只要DataFrame
很小,您假设put
进程比get
更快似乎是真的,我们就可以在while not q.empty()
的一个循环中获取所有5个项目。
但是,随着行数的增加,有些东西会发生变化。 while条件q.empty()
计算为True
(队列为空)和外while(1)
个周期。
这可能意味着put
现在比get
慢,我们必须等待。但是,如果我们将整个f_get
的休眠时间设置为15
,我们仍然可以获得相同的行为。
另一方面,如果我们将内部time.sleep(0)
循环中的q.get()
更改为1,
while not q.empty():
data = q.get()
time.sleep(1)
print "get (loop: %s)" %loop
loop += 1
我们得到了这个:
f_get start
f_put start
P: 0
P: 1
P: 2
P: 3
P: 4
get (loop: 0)
get (loop: 1)
get (loop: 2)
get (loop: 3)
get (loop: 4)
这看起来不错!这意味着实际上get
做了一些奇怪的事情。似乎虽然它仍在处理get
,但队列状态为empty
,在get
完成后,下一个项目可用。
我确定这是有原因的,但我对multiprocessing
不够熟悉。
根据您的应用程序,您可以将适当的time.sleep
添加到内部循环中,看看是否足够。
或者,如果您想解决它(而不是使用time.sleep
方法的解决方法),您可以查看multiprocessing
并查找有关阻止的信息, 非阻塞或异步通信 - 我认为可以在那里找到解决方案。