我有一份工作,我可以完成很多单独的任务。对于每个任务,我需要下载一些数据,处理它然后再次上传。
我正在使用多处理池进行处理。
我有几个我不确定的问题。
首先,数据大概可达20MB,理想情况下,我希望将其转移到子工作进程,而无需在内存中进行物理移动,并将结果数据返回到父进程,而无需移动它。由于我不确定某些工具是如何工作的,我不知道我是否可以将数据作为参数传递给池apply_async
(根据我的理解,它将对象序列化然后它们是一旦到达子流程再次创建?),或者我是否应该使用多处理Queue
或mmap
?或其他什么?
我查看了ctypes objects但是根据我的理解,只有在可以共享流程分支时创建池时定义的对象?这对我没有好处,因为我将继续有新的数据进入,我需要分享。
我不应该担心的一件事是对数据的任何并发访问,所以我不需要任何类型的锁定。这是因为处理只会在下载数据后开始,上传也只会在生成输出数据后开始。
我遇到的另一个问题是,有时候进入的任务可能会飙升,因此我会比子进程处理它更快地下载任务数据。因此,我下载的数据比我完成任务和处理数据更快,而python因内存不足而死亡。当内存几乎已满/在作业管道中有太多数据时,在下载阶段阻止任务的好方法是什么? 我通过使用数据字节数来考虑某种类型的“ref”计数,因此我可以限制下载和上载之间的数据量,并且只有在数量低于某个阈值时才下载。虽然我担心孩子有时可能会失败,但我永远不会把它带走的数据拿走了。有没有一种很好的方法来实现这种目标?
答案 0 :(得分:2)
以下是多处理documentation的简单示例:
来自多处理导入过程,值,数组
def f(n, a):
n.value = 3.1415927
for i in range(len(a)):
a[i] = -a[i]
if __name__ == '__main__':
num = Value('d', 0.0)
arr = Array('i', range(10))
p = Process(target=f, args=(num, arr))
p.start()
p.join()
print num.value
print arr[:]
请注意,num
和arr
是共享对象。这是你在找什么?
答案 1 :(得分:2)
(这是我之前回答的讨论结果)
您是否尝试过POSH
此示例显示可以将元素附加到可变列表,这可能是您想要的(从documentation复制):
import posh
l = posh.share(range(3))
if posh.fork():
#parent process
l.append(3)
posh.waitall()
else:
# child process
l.append(4)
posh.exit(0)
print l
-- Output --
[0, 1, 2, 3, 4]
-- OR --
[0, 1, 2, 4, 3]
答案 2 :(得分:0)
我一起破坏了这个,因为无论如何我需要为自己解决这个问题。在多处理或线程方面,我绝不是非常有成就,但至少它可行。也许它可以以更智能的方式完成,我无法弄清楚如何使用非原始Array
类型附带的锁。也许有人会建议改进评论。
from multiprocessing import Process, Event
from multiprocessing.sharedctypes import RawArray
def modify(s, task_event, result_event):
for i in range(4):
print "Worker: waiting for task"
task_event.wait()
task_event.clear()
print "Worker: got task"
s.value = s.value.upper()
result_event.set()
if __name__ == '__main__':
data_list = ("Data", "More data", "oh look, data!", "Captain Pickard")
task_event = Event()
result_event = Event()
s = RawArray('c', "X" * max(map(len, data_list)))
p = Process(target=modify, args=(s, task_event, result_event))
p.start()
for data in data_list:
s.value = data
task_event.set()
print "Sent new task. Waiting for results."
result_event.wait()
result_event.clear()
print "Got result: {0}".format(s.value)
p.join()
在此示例中,data_list
是事先定义的,但不一定是。我从该列表中获得的唯一信息是最长字符串的长度。只要你有一些长度的实际上限,就没问题了。
以下是该计划的输出:
Sent new task. Waiting for results. Worker: waiting for task Worker: got task Worker: waiting for task Got result: DATA Sent new task. Waiting for results. Worker: got task Worker: waiting for task Got result: MORE DATA Sent new task. Waiting for results. Worker: got task Worker: waiting for task Got result: OH LOOK, DATA! Sent new task. Waiting for results. Worker: got task Got result: CAPTAIN PICKARD
正如你所看到的,btel确实提供了解决方案,但问题在于保持两个进程彼此保持同步,这样工作人员只有在任务准备就绪时才开始处理新任务,所以主要过程在完成之前不会读取结果。