这可能是一个非常简单的问题,但绝对让我疲惫不堪。 为了使用多处理,我编写了以下代码。 main函数创建两个进程,它们都使用相同的函数,称为prepare_input_data(),但处理不同的输入数据集。此函数必须为每个输入返回多个对象和值,以便在代码的后续步骤中使用(此处不包括)。
我想要的是从多个处理中使用的函数返回多个值或对象。
def prepare_input_data(inputdata_address,temporary_address, output):
p=current_process()
name = p.name
data_address = inputdata_address
layer = loading_layer(data_address)
preprocessing_object = Preprocessing(layer)
nodes= preprocessing_object.node_extraction(layer)
tree = preprocessing_object.index_nodes()
roundabouts_dict , roundabouts_tree= find_roundabouts(layer.address, layer, temporary_address)
#return layer, nodes, tree, roundabouts_dict, roundabouts_tree
#return [layer, nodes, tree, roundabouts_dict, roundabouts_tree]
output.put( [layer, nodes, tree, roundabouts_dict, roundabouts_tree])
if __name__ == '__main__':
print "the data preparation in multi processes starts here"
output=Queue()
start_time=time.time()
processes =[]
#outputs=[]
ref_process = Process(name ="reference", target=prepare_input_data, args=("D:/Ehsan/Skane/Input/Skane_data/Under_processing/identicals/clipped/test/NVDB_test3.shp", "D:/Ehsan/Skane/Input/Skane_data/Under_processing/temporary/",output))
cor_process = Process(name ="corresponding", target=prepare_input_data, args=("D:/Ehsan/Skane/Input/Skane_data/Under_processing/identicals/clipped/test/OSM_test3.shp", "D:/Ehsan/Skane/Input/Skane_data/Under_processing/temporary/",output))
#outputs.append(ref_process.start)
#outputs.append(cor_process.start)
ref_process.start
cor_process.start
processes.append(ref_process)
processes.append(cor_process)
for p in processes:
p.join()
print "the whole data preparation took ",time.time()-start_time
results={}
for p in processes:
results[p.name]=output.get()
########################
#ref_info = outputs[0]
# ref_nodes=ref_info[0]
以前的错误 当我使用return时,ref_info [0]有Nonetype。
错误: 基于答案here我将其更改为传递给函数的Queueu对象,然后我使用put()添加结果,并使用get()来检索它们以进行进一步处理。
Traceback (most recent call last):
File "C:\Python27\ArcGISx6410.2\Lib\multiprocessing\queues.py", line 262, in _feed
send(obj)
UnpickleableError: Cannot pickle <type 'geoprocessing spatial reference object'> objects
你能帮我解决一下如何从多处理函数中返回多个值吗?
答案 0 :(得分:0)
使用共享状态进行并行编程是一条艰难的道路,即使是经验丰富的程序员也会出错。一个更适合初学者的方法是复制数据。这是在子进程之间移动数据的唯一方法(不完全正确,但这是一个高级主题)。
引用https://docs.python.org/2/library/multiprocessing.html#exchanging-objects-between-processes,您需要设置multiprocessing.Queue以填充每个子进程的返回数据。之后,您可以将队列传递给下一阶段。
对于多个不同的数据集,例如图层,节点,树等,您可以使用多个队列来区分每个返回值。为每个队列使用队列似乎有些混乱,但它简单易懂且安全。
希望有所帮助。
答案 1 :(得分:0)
如果你使用 jpe_types.parallel 的 Process,它会像这样返回 Processes 目标函数的返回值
import jpe_types.paralel
def fun():
return 4, 23.4, "hi", None
if __name__ == "__main__":
p = jpe_types.paralel.Process(target = fun)
p.start()
print(p.join())
否则你可以
import multiprocessing as mp
def fun(returner):
returner.send((1, 23,"hi", None))
if __name__ == "__main__":
processes = []
for i in range(2):
sender, recever = mp.Pipe()
p = mp.Process(target = fun, args=(sender,))
p.start()
processes.append((p, recever))
resses = []
for p, rcver in processes:
p.join()
resses.append(rcver.recv())
print(resses)
使用连接将保证 retun 不会乱码
答案 2 :(得分:-2)
如果您希望从multiprocessing
获得多个返回值,那么您可以这样做。这是一个简单的例子,首先是串行python,然后是multiprocessing
:
>>> a,b = range(10), range(10,0,-1)
>>> import math
>>> map(math.modf, (1.*i/j for i,j in zip(a,b)))
[(0.0, 0.0), (0.1111111111111111, 0.0), (0.25, 0.0), (0.42857142857142855, 0.0), (0.6666666666666666, 0.0), (0.0, 1.0), (0.5, 1.0), (0.3333333333333335, 2.0), (0.0, 4.0), (0.0, 9.0)]
>>>
>>> from multiprocessing import Pool
>>> res = Pool().imap(math.modf, (1.*i/j for i,j in zip(a,b)))
>>> for i,ai in enumerate(a):
... x,y = res.next()
... print("{x},{y} = modf({u}/{d})").format(x=x,y=y,u=ai,d=b[i])
...
0.0,0.0 = modf(0/10)
0.111111111111,0.0 = modf(1/9)
0.25,0.0 = modf(2/8)
0.428571428571,0.0 = modf(3/7)
0.666666666667,0.0 = modf(4/6)
0.0,1.0 = modf(5/5)
0.5,1.0 = modf(6/4)
0.333333333333,2.0 = modf(7/3)
0.0,4.0 = modf(8/2)
0.0,9.0 = modf(9/1)
因此,要在具有multiprocessing
的函数的返回中获取多个值,您只需要一个返回多个值的函数...您只需将这些值作为元组列表返回。
multiprocessing
的主要问题,正如您从错误中看到的那样......大多数函数都没有序列化。所以,如果你真的想做你想做的事情......我强烈建议你使用pathos
(如下所述)。使用multiprocessing
时最大的障碍是,作为目标传递的函数必须可序列化。您可以对prepare_input_data
函数进行一些修改...第一个是确保它被封装。如果你的函数没有完全封装(例如,它的名称引用查找超出了它自己的范围),那么它可能不会用pickle
来腌制。这意味着,您需要在目标函数中包含所有导入,并通过函数输入传递任何其他变量。您看到的错误(UnPicklableError
)是由于您的目标函数及其依赖项无法序列化 - 而不是您无法从multiprocessing
返回多个值。
虽然我将封装目标函数作为一种良好的实践,但它可能有点单调乏味并且可能会减慢代码的速度。我还建议您将代码转换为使用dill
和pathos.multiprocessing
- dill
是一个可以腌制几乎所有python对象的高级序列化程序,pathos
提供multiprocessing
1}}使用dill
的fork。这样,您可以传递pipe
中的大多数python对象(即apply
)或map
对象中可用的Pool
,并且不要过多担心出汗难以重构您的代码,以确保普通的旧pickle
和multiprocessing
可以处理它。
另外,我使用异步map
而不是做你上面做的事情。 pathos.multiprocessing
能够在map
函数中使用多个参数,因此您无需像上面那样将它们包装在元组args
中。使用异步map
时接口应该更干净,如果需要,可以返回多个参数...只需将它们打包成元组。
这里有一些例子可以证明我上面提到的内容。
返回多个值:
>>> from pathos.multiprocessing import ProcessingPool as Pool
>>> def addsub(x,y):
... return x+y, x-y
...
>>> a,b = range(10),range(-10,10,2)
>>> res = Pool().imap(addsub, a, b)
>>>
>>> for i,ai in enumerate(a):
... add,sub = res.next()
... print("{a} + {b} = {p}; {a} - {b} = {m}".format(a=ai,b=b[i],p=add,m=sub))
...
0 + -10 = -10; 0 - -10 = 10
1 + -8 = -7; 1 - -8 = 9
2 + -6 = -4; 2 - -6 = 8
3 + -4 = -1; 3 - -4 = 7
4 + -2 = 2; 4 - -2 = 6
5 + 0 = 5; 5 - 0 = 5
6 + 2 = 8; 6 - 2 = 4
7 + 4 = 11; 7 - 4 = 3
8 + 6 = 14; 8 - 6 = 2
9 + 8 = 17; 9 - 8 = 1
>>>
异步地图: Python multiprocessing - tracking the process of pool.map operation
pathos
:
Can't pickle <type 'instancemethod'> when using python's multiprocessing Pool.map()
pathos
:
What can multiprocessing and dill do together?
我们仍然无法运行您的代码...但如果您发布可以运行的代码,则可能更有可能帮助编辑您的代码(使用pathos
分叉和异步map
或其他方式)。
仅供参考:pathos
的版本有点过期(即迟到),所以如果您想尝试一下,最好在此处获取代码:https://github.com/uqfoundation