簡體   English   中英

使用python的多處理並行處理具有多個list參數的函數

[英]Parallelizing a function with multiple lists arguments with python's multiprocessing

我希望這不是重復的,但是對於這個特定的問題,我找不到一個完全令人滿意的答案。

給定一個具有多個列表參數且一個可迭代的函數,例如此處具有兩個列表

def function(list1, list2, iterable):
    i1 = 2*iterable
    i2 = 2*iterable+1
    list1[i1] *= 2
    list2[i2] += 2
    return(list1, list2)

每個列表都在不同的條目處訪問,因此操作是分開的並且可以並行化。 用python的多處理方法做到這一點的最佳方法是什么?

一種簡單的並行化方法是使用map函數:

import multiprocessing as mp
from functools import partial

list1, list2 = [1,1,1,1,1], [2,2,2,2,2]
func = partial(function, list1, list2)
pool = mp.Pool()
pool.map(func, [0,1])

問題是如果這樣做的話,每個過程都會產生一份列表的副本(如果我理解地圖功能的話),然后在這些副本的不同位置並行工作。 最后(觸摸了兩個可迭代變量[0,1]之后),pool.map的結果為

[([3, 1, 1, 1, 1], [2, 4, 2, 2, 2]), ([1, 1, 3, 1, 1], [2, 2, 2, 4, 2])]

但我想要

[([3, 1, 3, 1, 1], [2, 4, 2, 4, 2])].

如何實現呢? 是否應該在之前以可迭代的方式拆分列表,並行運行特定操作,然后再次合並它們?

在此先感謝您,如果我混淆了一點,請開始使用multiprocessing-library。

編輯:列表上不同部分的操作可以不同步而被並行化,整個列表上的操作也不能被並行化(不同步)。 因此,針對我的特定問題的解決方案是將列表和函數拆分為操作和列表的各個部分。 之后,合並列表的各個部分以重新獲得整個列表。

您不能在進程之間共享內存(從技術上講,您可以在基於fork的系統上共享,前提是您不更改對象/影響引用計數,而這在現實世界中很少發生)-您可以選擇使用共享結構(它們中的大多數都在multiprocessing.Manager()下可用,它將為您執行同步/更新,或者僅傳遞處理所需的數據,然后將結果縫合在一起。

您的示例很簡單,可以使兩種方法都能正常工作而不會受到嚴厲的處罰,因此我只想和一位經理一起:

import multiprocessing
import functools

def your_function(list1, list2, iterable):
    i1 = 2 * iterable
    i2 = 2 * iterable + 1
    list1[i1] *= 2
    list2[i2] += 2

if __name__ == "__main__":  # a multi-processing guard for cross-platform use
    manager = multiprocessing.Manager()
    l1 = manager.list([1, 1, 1, 1, 1])
    l2 = manager.list([2, 2, 2, 2, 2])
    func = functools.partial(your_function, l1, l2)
    pool = multiprocessing.Pool()
    pool.map(func, [0, 1])
    print(l1, l2)  # [2, 1, 2, 1, 1] [2, 4, 2, 4, 2]

或者,如果您的用例更適合於在處理后縫合數據:

import multiprocessing
import functools

def your_function(list1, list2, iterable):
    i1 = 2 * iterable
    i2 = 2 * iterable + 1
    return (i1, list1[i1] * 2), (i2, list2[i2] + 2)  # return the changed index and value

if __name__ == "__main__":  # a multi-processing guard for cross-platform use
    l1 = [1, 1, 1, 1, 1]
    l2 = [2, 2, 2, 2, 2]
    func = functools.partial(your_function, l1, l2)
    pool = multiprocessing.Pool()
    results = pool.map(func, [0, 1])
    for r1, r2 in results:  # stitch the results back into l1 and l2
        l1[r1[0]] = r1[1]
        l2[r2[0]] = r2[1]
    print(l1, l2)  # [2, 1, 2, 1, 1] [2, 4, 2, 4, 2]

話雖這么說,輸出不是您列出/期望的結果,而是根據您的功能應該發生的結果。

同樣,如果您的情況如此簡單,則可能希望完全避免進行多處理-除非您的your_function()確實執行了一些CPU密集型任務,否則增加的多處理(加上管理器同步)是不值得的。

這里是解決問題的方法。 我不知道這是否是最好的方法,但是它有效:

import multiprocessing as mp
from functools import partial

def operation1(lst, pos)
    return(pos, lst[pos] * 2)

def operation2(lst, pos)
    return(pos, lst[pos] + 2)

if __name__ == "__main__":
    list1, list2 = [1,1,1,1,1], [2,2,2,2,2]
    iterable = [0,1]
    index1_list = [2*i for i in iterable]
    index2_list = [2*i+1 for i in iterable]

    func1 = partial(operation1, list1)
    func2 = partial(operation2, list2)

    with mp.Pool() as pool:
        result1 = pool.map(func1, index1_list)
        result2 = pool.map(func2, index2_list)

    for result in result1:
        list1[result[0]] = result[1]

    for result in result2:
        list2[result[0]] = result[1]

    print(list1, list2)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM