我有一个关于Python多处理的问题。我试图获取一个数据集,分成几个块,然后将这些块传递给并发运行的进程。我需要使用简单的计算来转换大型数据表(例如,电阻 - >热敏电阻的温度)。
下面列出的代码几乎可以按预期工作,但它似乎不会产生任何新进程(或者如果一次只有一个进程)。我是Python的新手,所以对这个问题可能有一个非常简单的解决方案。
提前致谢!
from multiprocessing import Process class Worker(Process): # example data transform def process(self, x): return (x * 2) / 3 def __init__(self, list): self.data = list self.result = map(self.process, self.data) super(Worker, self).__init__() if __name__ == '__main__': start = datetime.datetime.now() dataset = range(10000) # null dataset processes = 3 for i in range(processes): chunk = int(math.floor(len(dataset) / float(processes))) if i + 1 == processes: remainder = len(dataset) % processes else: remainder = 0 tmp = dataset[i * chunk : (i + 1) * chunk + remainder] exec('worker'+str(i)+' = Worker(tmp)') exec('worker'+str(i)+'.start()') for i in range(processes): exec('worker'+str(i)+'.join()') # just a placeholder to make sure the initial values of the set are as expected exec('print worker'+str(i)+'.result[0]')
答案 0 :(得分:1)
您尚未覆盖run
方法。进程(或线程)有两种方法可以让它执行代码:
run
方法。覆盖__init__
只意味着您的流程无处可去。它应该用于为它提供执行所需执行的属性,但不应指定要执行的任务。
在你的代码中,所有繁重的工作都在这一行完成:
exec('worker'+str(i)+' = Worker(tmp)')
这里没有做任何事情:
exec('worker'+str(i)+'.start()')
因此,使用exec('print worker'+str(i)+'.result[0]')
检查结果应该会给你一些有意义的东西,但这只是因为你想要执行的代码已经执行了,但是在流程构建上,而不是在流程启动时。
试试这个:
class Worker(Process):
# example data transform
def process(self, x): return (x * 2) / 3
def __init__(self, list):
self.data = list
self.result = []
super(Worker, self).__init__()
def run(self):
self.result = map(self.process, self.data)
编辑:
好吧......所以我只是根据我的线程本能飞行,他们都错了。我们都不了解流程的是你无法直接共享变量。无论您传递给新流程的是什么,都会被阅读,复制并永远消失。除非您使用两种标准方式之一来共享数据:queues and pipes。我玩了一下试图让你的代码工作,但到目前为止没有运气。我想这会让你走上正轨。
答案 1 :(得分:1)
无需向每个进程发送块数,只需使用get_nowait()并处理最终的Queue.Empty异常。每个进程都会获得不同的CPU时间,这应该让他们都忙着。
import multiprocessing, Queue
class Worker(multiprocessing.Process):
def process(self, x):
for i in range(15):
x += (float(i) / 2.6)
return x
def __init__(self, input, output):
self.input = input
self.output = output
super(Worker, self).__init__()
def run(self):
try:
while True:
self.output.put(self.process(self.input.get_nowait()))
except Queue.Empty:
pass
if name == 'main':
dataset = range(10)
processes = multiprocessing.cpu_count()
input = multiprocessing.Queue()
output = multiprocessing.Queue()
for obj in dataset:
input.put(obj)
for i in range(processes):
Worker(input, output).start()
for i in range(len(dataset)):
print output.get()
答案 2 :(得分:0)
好的,所以看起来这个列表不是线程安全的,我已经开始使用Queue了(尽管看起来要慢很多)。这段代码基本上完成了我想要做的事情:
import math, multiprocessing
class Worker(multiprocessing.Process):
def process(self, x):
for i in range(15):
x += (float(i) / 2.6)
return x
def __init__(self, input, output, chunksize):
self.input = input
self.output = output
self.chunksize = chunksize
super(Worker, self).__init__()
def run(self):
for x in range(self.chunksize):
self.output.put(self.process(self.input.get()))
if __name__ == '__main__':
dataset = range(10)
processes = multiprocessing.cpu_count()
input = multiprocessing.Queue()
output = multiprocessing.Queue()
for obj in dataset:
input.put(obj)
for i in range(processes):
chunk = int(math.floor(len(dataset) / float(processes)))
if i + 1 == processes:
remainder = len(dataset) % processes
else: remainder = 0
Worker(input, output, chunk + remainder).start()
for i in range(len(dataset)):
print output.get()