Python มัลติโพรเซสซิง pool.map สำหรับหลาย ๆ อาร์กิวเมนต์


536

ใน Python Multrocessing library มีตัวแปรของ pool.map ซึ่งรองรับหลายอาร์กิวเมนต์หรือไม่

text = "test"
def harvester(text, case):
    X = case[0]
    text+ str(X)

if __name__ == '__main__':
    pool = multiprocessing.Pool(processes=6)
    case = RAW_DATASET
    pool.map(harvester(text,case),case, 1)
    pool.close()
    pool.join()

4
ที่แปลกใจของฉันฉันจะทำให้ค่าpartialมิได้lambdaทำเช่นนี้ ฉันคิดว่ามันเกี่ยวข้องกับวิธีแปลก ๆ ที่ฟังก์ชั่นถูกส่งผ่านไปยังกระบวนการย่อย (ผ่านpickle)
senderle

10
@senderle: นี่เป็นข้อผิดพลาดใน Python 2.6 แต่ได้รับการแก้ไขตั้งแต่ 2.7: bugs.python.org/issue5228
unutbu

1
เพียงแค่แทนที่ pool.map(harvester(text,case),case, 1) ด้วย: pool.apply_async(harvester(text,case),case, 1)
ตุ้งเหงียน

3
@Syrtis_Major โปรดอย่าแก้ไขคำถาม OP ซึ่งตอบโจทย์ได้อย่างมีประสิทธิภาพซึ่งได้ให้ไว้ก่อนหน้านี้ การเพิ่มreturnการตอบharvester()กลับของ @senderie กลายเป็นการไม่ถูกต้อง นั่นไม่ได้ช่วยผู้อ่านในอนาคต
Ricalsin

1
ฉันจะบอกว่าทางออกง่าย ๆ คือการแพ็ค args ทั้งหมดใน tuple และแกะมันออกมาใน func ที่กำลังดำเนินการ ฉันทำสิ่งนี้เมื่อฉันต้องการส่ง args หลาย ๆ อันที่ซับซ้อนไปยัง func ที่ถูกดำเนินการโดยกลุ่มของกระบวนการ
HS Rathore

คำตอบ:


358

คำตอบสำหรับเรื่องนี้คือเวอร์ชั่น - และขึ้นอยู่กับสถานการณ์ คำตอบทั่วไปมากที่สุดสำหรับรุ่นล่าสุดของงูใหญ่ (ตั้งแต่ 3.3) เป็นครั้งแรกที่อธิบายไว้ด้านล่างโดยJF เซบาสเตียน 1มันใช้Pool.starmapวิธีการซึ่งยอมรับลำดับของสิ่งอันดับอาร์กิวเมนต์ จากนั้นจะคลายการขัดแย้งจากแต่ละทูเปิลและส่งผ่านไปยังฟังก์ชันที่กำหนด:

import multiprocessing
from itertools import product

def merge_names(a, b):
    return '{} & {}'.format(a, b)

if __name__ == '__main__':
    names = ['Brown', 'Wilson', 'Bartlett', 'Rivera', 'Molloy', 'Opie']
    with multiprocessing.Pool(processes=3) as pool:
        results = pool.starmap(merge_names, product(names, repeat=2))
    print(results)

# Output: ['Brown & Brown', 'Brown & Wilson', 'Brown & Bartlett', ...

สำหรับ Python เวอร์ชันก่อนหน้าคุณจะต้องเขียนฟังก์ชันตัวช่วยเพื่อคลายข้อโต้แย้งอย่างชัดเจน หากคุณต้องการใช้withคุณจะต้องเขียน wrapper เพื่อเปลี่ยนPoolเป็น context manager (ขอบคุณmuon ที่ชี้เรื่องนี้ออกมา)

import multiprocessing
from itertools import product
from contextlib import contextmanager

def merge_names(a, b):
    return '{} & {}'.format(a, b)

def merge_names_unpack(args):
    return merge_names(*args)

@contextmanager
def poolcontext(*args, **kwargs):
    pool = multiprocessing.Pool(*args, **kwargs)
    yield pool
    pool.terminate()

if __name__ == '__main__':
    names = ['Brown', 'Wilson', 'Bartlett', 'Rivera', 'Molloy', 'Opie']
    with poolcontext(processes=3) as pool:
        results = pool.map(merge_names_unpack, product(names, repeat=2))
    print(results)

# Output: ['Brown & Brown', 'Brown & Wilson', 'Brown & Bartlett', ...

ในกรณีที่ง่ายกว่าด้วยอาร์กิวเมนต์ที่สองคงที่คุณสามารถใช้partialแต่เฉพาะใน Python 2.7+

import multiprocessing
from functools import partial
from contextlib import contextmanager

@contextmanager
def poolcontext(*args, **kwargs):
    pool = multiprocessing.Pool(*args, **kwargs)
    yield pool
    pool.terminate()

def merge_names(a, b):
    return '{} & {}'.format(a, b)

if __name__ == '__main__':
    names = ['Brown', 'Wilson', 'Bartlett', 'Rivera', 'Molloy', 'Opie']
    with poolcontext(processes=3) as pool:
        results = pool.map(partial(merge_names, b='Sons'), names)
    print(results)

# Output: ['Brown & Sons', 'Wilson & Sons', 'Bartlett & Sons', ...

1. สิ่งนี้ได้รับแรงบันดาลใจจากคำตอบของเขาซึ่งน่าจะได้รับการยอมรับแทน แต่เนื่องจากอันนี้ติดอยู่ที่ด้านบนสุดจึงเป็นการดีที่สุดที่จะปรับปรุงสำหรับผู้อ่านในอนาคต


ฉันว่า RAW_DATASET ในกรณีนี้ควรเป็นตัวแปรทั่วโลกหรือไม่ ในขณะที่ฉันต้องการ partial_harvester เปลี่ยนค่าของ case ในการเรียกของ harvester () ทุกครั้ง ทำอย่างไรถึงจะบรรลุเป้าหมายนั้น?
xgdgsc

สิ่งที่สำคัญที่สุดที่นี่คือการกำหนดค่าเริ่มต้นให้กับ=RAW_DATASET caseมิฉะนั้นpool.mapจะสร้างความสับสนเกี่ยวกับข้อโต้แย้งหลาย ๆ
Emerson Xu

1
ฉันสับสนเกิดอะไรขึ้นกับtextตัวแปรในตัวอย่างของคุณ ทำไมRAW_DATASETดูเหมือนผ่านสองครั้ง ฉันคิดว่าคุณอาจพิมพ์ผิดหรือไม่?
เดฟ

ไม่แน่ใจว่าทำไมการใช้with .. as .. ให้ฉันAttributeError: __exit__แต่ใช้งานได้ดีถ้าฉันโทรpool = Pool();แล้วปิดเองpool.close()(python2.7)
muon

1
@muon จับได้ดี ดูเหมือนว่าPoolวัตถุจะไม่กลายเป็นตัวจัดการบริบทจนกว่า Python 3.3 ฉันได้เพิ่มฟังก์ชั่น wrapper ง่าย ๆ ที่คืนค่าตัวPoolจัดการบริบท
senderle

501

จะมีตัวแปรของ pool.map ซึ่งรองรับหลายอาร์กิวเมนต์หรือไม่

Python 3.3 รวมถึงpool.starmap()วิธีการ :

#!/usr/bin/env python3
from functools import partial
from itertools import repeat
from multiprocessing import Pool, freeze_support

def func(a, b):
    return a + b

def main():
    a_args = [1,2,3]
    second_arg = 1
    with Pool() as pool:
        L = pool.starmap(func, [(1, 1), (2, 1), (3, 1)])
        M = pool.starmap(func, zip(a_args, repeat(second_arg)))
        N = pool.map(partial(func, b=second_arg), a_args)
        assert L == M == N

if __name__=="__main__":
    freeze_support()
    main()

สำหรับรุ่นเก่า:

#!/usr/bin/env python2
import itertools
from multiprocessing import Pool, freeze_support

def func(a, b):
    print a, b

def func_star(a_b):
    """Convert `f([1,2])` to `f(1,2)` call."""
    return func(*a_b)

def main():
    pool = Pool()
    a_args = [1,2,3]
    second_arg = 1
    pool.map(func_star, itertools.izip(a_args, itertools.repeat(second_arg)))

if __name__=="__main__":
    freeze_support()
    main()

เอาท์พุต

1 1
2 1
3 1

สังเกตวิธีitertools.izip()และitertools.repeat()ใช้ที่นี่

เนื่องจากข้อผิดพลาดที่กล่าวถึงโดย @unutbuคุณไม่สามารถใช้functools.partial()หรือความสามารถที่คล้ายกันใน Python 2.6 ดังนั้นfunc_star()ควรกำหนดฟังก์ชั่น wrapper อย่างง่าย ดูเพิ่มเติมการแก้ปัญหา ที่แนะนำโดยuptimebox


1
F .: คุณสามารถแกะ tuple โต้แย้งในลายเซ็นของเช่นนี้func_star def func_star((a, b))แน่นอนว่าวิธีนี้ใช้ได้กับจำนวนอาร์กิวเมนต์ที่คงที่เท่านั้น แต่หากเป็นกรณีเดียวที่เขามีก็จะสามารถอ่านได้มากขึ้น
Björn Pollex

1
@ Space_C0wb0y: f((a,b))ไวยากรณ์เลิกใช้แล้วและถูกลบใน py3k และมันไม่จำเป็นที่นี่
jfs

บางทีอาจจะfunc = lambda x: func(*x)เป็น
ไพทอน

1
@ zthomas.nc คำถามนี้เกี่ยวกับวิธีการสนับสนุนอาร์กิวเมนต์หลายตัวสำหรับการประมวลผลทวีคูณ pool.map หากต้องการทราบวิธีการที่จะเรียกวิธีการแทนของฟังก์ชั่นในกระบวนการหลามที่แตกต่างกันทาง multiprocessing แล้วถามคำถามที่แยกต่างหาก (ถ้าทุกคนอื่นไม่คุณก็สามารถสร้างฟังก์ชั่นระดับโลกที่ล้อมเรียกวิธีการคล้ายกับfunc_star()ด้านบน)
JFS

1
starstarmapฉันต้องการมี
КонстантинВан

141

ฉันคิดว่าด้านล่างจะดีกว่า

def multi_run_wrapper(args):
   return add(*args)
def add(x,y):
    return x+y
if __name__ == "__main__":
    from multiprocessing import Pool
    pool = Pool(4)
    results = pool.map(multi_run_wrapper,[(1,2),(2,3),(3,4)])
    print results

เอาท์พุต

[3, 5, 7]

16
ทางออกที่ง่ายที่สุด มีการเพิ่มประสิทธิภาพเล็กน้อย ลบฟังก์ชั่น wrapper และแกะออกargsโดยตรงaddมันทำงานได้กับจำนวนของข้อโต้แย้งใด ๆ :def add(args): (x,y) = args
อาเหม็ด

1
คุณสามารถใช้lambdaฟังก์ชั่นแทนการกำหนดได้multi_run_wrapper(..)
Andre Holzner

2
หืม ... อันที่จริงแล้วการใช้ a lambdaไม่ทำงานเพราะpool.map(..)พยายามที่จะดองฟังก์ชั่นที่กำหนด
Andre Holzner

คุณจะใช้สิ่งนี้ได้อย่างไรถ้าคุณต้องการเก็บผลลัพธ์addไว้ในรายการ?
Vivek Subramanian

@ อาเหม็ดฉันชอบมันมากเพราะ IMHO การเรียกเมธอดควรล้มเหลวเมื่อใดก็ตามที่จำนวนพารามิเตอร์ไม่ถูกต้อง
Michael Dorner

56

ใช้Python 3.3+กับpool.starmap():

from multiprocessing.dummy import Pool as ThreadPool 

def write(i, x):
    print(i, "---", x)

a = ["1","2","3"]
b = ["4","5","6"] 

pool = ThreadPool(2)
pool.starmap(write, zip(a,b)) 
pool.close() 
pool.join()

ผลลัพธ์:

1 --- 4
2 --- 5
3 --- 6

คุณยังสามารถซิป () อาร์กิวเมนต์เพิ่มเติมได้หากต้องการ: zip(a,b,c,d,e)

ในกรณีที่คุณต้องการให้ค่าคงที่ถูกส่งผ่านเป็นอาร์กิวเมนต์คุณต้องใช้import itertoolsแล้วzip(itertools.repeat(constant), a)เช่น


2
นี่เป็นคำตอบที่ใกล้เคียงที่สุดอย่างแน่นอนซึ่งเป็นคำตอบเดียวจาก @JFSebastian ในปี 2011 (ด้วยคะแนน 60+)
Mike McKerns

29
ไม่ก่อนอื่นมันเอาสิ่งที่ไม่จำเป็นออกมากมายและระบุอย่างชัดเจนว่ามันคือ python 3.3+ และมีไว้สำหรับผู้เริ่มต้นที่มองหาคำตอบที่ง่ายและสะอาด ในฐานะผู้เริ่มต้นฉันใช้เวลาพอสมควรกว่าจะคิดออกว่าใช่ (กับ JFSebastians โพสต์) และนี่คือเหตุผลที่ฉันเขียนโพสต์ของฉันเพื่อช่วยผู้เริ่มต้นคนอื่นเพราะโพสต์ของเขาบอกว่า "มี starmap" แต่ไม่ได้อธิบาย เป็นสิ่งที่โพสต์ของฉันตั้งใจ ดังนั้นจึงไม่มีเหตุผลใดที่จะทุบตีฉันด้วยสอง downvotes
136036

ในปี 2011 ไม่มี "+" ใน python 3.3 + …เห็นได้ชัดเลย
Mike McKerns

27

หลังจากได้เรียนรู้เกี่ยวกับ itertools ในJF Sebastianคำตอบฉันตัดสินใจที่จะก้าวไปอีกขั้นและเขียนparmapแพ็คเกจที่ใส่ใจเกี่ยวกับการขนานการเสนอmapและstarmapฟังก์ชั่นใน python-2.7 และ python-3.2 (และหลังจากนั้น) ที่สามารถโต้แย้งได้หลายตำแหน่ง .

การติดตั้ง

pip install parmap

วิธีการขนาน:

import parmap
# If you want to do:
y = [myfunction(x, argument1, argument2) for x in mylist]
# In parallel:
y = parmap.map(myfunction, mylist, argument1, argument2)

# If you want to do:
z = [myfunction(x, y, argument1, argument2) for (x,y) in mylist]
# In parallel:
z = parmap.starmap(myfunction, mylist, argument1, argument2)

# If you want to do:
listx = [1, 2, 3, 4, 5, 6]
listy = [2, 3, 4, 5, 6, 7]
param = 3.14
param2 = 42
listz = []
for (x, y) in zip(listx, listy):
        listz.append(myfunction(x, y, param1, param2))
# In parallel:
listz = parmap.starmap(myfunction, zip(listx, listy), param1, param2)

ผมได้อัพโหลด parmap เพื่อ PyPI และในพื้นที่เก็บข้อมูล GitHub

ตัวอย่างสามารถตอบคำถามได้ดังนี้:

import parmap

def harvester(case, text):
    X = case[0]
    text+ str(X)

if __name__ == "__main__":
    case = RAW_DATASET  # assuming this is an iterable
    parmap.map(harvester, case, "test", chunksize=1)

20

# "วิธีรับหลายอาร์กิวเมนต์"

def f1(args):
    a, b, c = args[0] , args[1] , args[2]
    return a+b+c

if __name__ == "__main__":
    import multiprocessing
    pool = multiprocessing.Pool(4) 

    result1 = pool.map(f1, [ [1,2,3] ])
    print(result1)

2
เรียบร้อยและสง่างาม
Prav001

1
ฉันไม่เข้าใจว่าทำไมฉันต้องเลื่อนไปทางนี้เพื่อหาคำตอบที่ดีที่สุด
toti

11

มีทางแยกที่multiprocessingเรียกว่าสิ่งที่น่าสมเพช ( หมายเหตุ: ใช้เวอร์ชันบน github ) ที่ไม่จำเป็นstarmap- ฟังก์ชั่นแผนที่ทำหน้าที่สะท้อน API ของแผนที่ของงูใหญ่ดังนั้นแผนที่สามารถใช้อาร์กิวเมนต์หลายตัวได้ ด้วยpathosโดยทั่วไปคุณสามารถทำการประมวลผลหลายตัวในล่ามแทนที่จะติดอยู่ใน__main__บล็อก สิ่งที่น่าสมเพชมีกำหนดสำหรับการเปิดตัวหลังจากการปรับปรุงเล็กน้อย - การแปลงส่วนใหญ่เป็นงูหลาม 3.x

  Python 2.7.5 (default, Sep 30 2013, 20:15:49) 
  [GCC 4.2.1 (Apple Inc. build 5566)] on darwin
  Type "help", "copyright", "credits" or "license" for more information.
  >>> def func(a,b):
  ...     print a,b
  ...
  >>>
  >>> from pathos.multiprocessing import ProcessingPool    
  >>> pool = ProcessingPool(nodes=4)
  >>> pool.map(func, [1,2,3], [1,1,1])
  1 1
  2 1
  3 1
  [None, None, None]
  >>>
  >>> # also can pickle stuff like lambdas 
  >>> result = pool.map(lambda x: x**2, range(10))
  >>> result
  [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
  >>>
  >>> # also does asynchronous map
  >>> result = pool.amap(pow, [1,2,3], [4,5,6])
  >>> result.get()
  [1, 32, 729]
  >>>
  >>> # or can return a map iterator
  >>> result = pool.imap(pow, [1,2,3], [4,5,6])
  >>> result
  <processing.pool.IMapIterator object at 0x110c2ffd0>
  >>> list(result)
  [1, 32, 729]

pathosstarmapมีหลายวิธีที่คุณจะได้รับพฤติกรรมที่แท้จริงของ

>>> def add(*x):
...   return sum(x)
... 
>>> x = [[1,2,3],[4,5,6]]
>>> import pathos
>>> import numpy as np
>>> # use ProcessPool's map and transposing the inputs
>>> pp = pathos.pools.ProcessPool()
>>> pp.map(add, *np.array(x).T)
[6, 15]
>>> # use ProcessPool's map and a lambda to apply the star
>>> pp.map(lambda x: add(*x), x)
[6, 15]
>>> # use a _ProcessPool, which has starmap
>>> _pp = pathos.pools._ProcessPool()
>>> _pp.starmap(add, x)
[6, 15]
>>> 

ฉันต้องการที่จะทราบว่านี่ไม่ได้อยู่โครงสร้างในคำถามเดิม [[1,2,3], [4,5,6]] จะแกะด้วย starmap ถึง [pow (1,2,3), pow (4,5,6)] ไม่ใช่ [pow (1,4) , pow (2,5), pow (3, 6)] หากคุณไม่สามารถควบคุมอินพุตที่ส่งไปยังฟังก์ชันของคุณได้เป็นอย่างดีคุณอาจต้องปรับโครงสร้างเหล่านั้นก่อน
สกอตต์

@Scott: อ่าฉันไม่ได้สังเกตว่า ... มากกว่า 5 ปีที่แล้ว ฉันจะทำให้การปรับปรุงเล็กน้อย ขอบคุณ
Mike McKerns

8

คุณสามารถใช้สองฟังก์ชันต่อไปนี้เพื่อหลีกเลี่ยงการเขียน wrapper สำหรับแต่ละฟังก์ชั่นใหม่:

import itertools
from multiprocessing import Pool

def universal_worker(input_pair):
    function, args = input_pair
    return function(*args)

def pool_args(function, *args):
    return zip(itertools.repeat(function), zip(*args))

ใช้ฟังก์ชั่นfunctionที่มีรายการของการขัดแย้งarg_0, arg_1และarg_2ดังต่อไปนี้:

pool = Pool(n_core)
list_model = pool.map(universal_worker, pool_args(function, arg_0, arg_1, arg_2)
pool.close()
pool.join()

8

ทางออกที่ดีกว่าสำหรับ python2:

from multiprocessing import Pool
def func((i, (a, b))):
    print i, a, b
    return a + b
pool = Pool(3)
pool.map(func, [(0,(1,2)), (1,(2,3)), (2,(3, 4))])

2 3 4

1 2 3

0 1 2

ออก[]:

[3, 5, 7]


7

อีกทางเลือกง่าย ๆ คือห่อพารามิเตอร์ฟังก์ชั่นของคุณในสิ่งอันดับแล้วห่อพารามิเตอร์ที่ควรจะส่งผ่านในสิ่งอันดับเช่นกัน นี่อาจไม่เหมาะเมื่อจัดการกับข้อมูลขนาดใหญ่ ฉันเชื่อว่ามันจะทำสำเนาสำหรับแต่ละ tuple

from multiprocessing import Pool

def f((a,b,c,d)):
    print a,b,c,d
    return a + b + c +d

if __name__ == '__main__':
    p = Pool(10)
    data = [(i+0,i+1,i+2,i+3) for i in xrange(10)]
    print(p.map(f, data))
    p.close()
    p.join()

ให้ผลลัพธ์ในบางลำดับแบบสุ่ม:

0 1 2 3
1 2 3 4
2 3 4 5
3 4 5 6
4 5 6 7
5 6 7 8
7 8 9 10
6 7 8 9
8 9 10 11
9 10 11 12
[6, 10, 14, 18, 22, 26, 30, 34, 38, 42]

แน่นอนมันยังคงมองหาวิธีที่ดีกว่า :(
Fábio Dias

6

วิธีที่ดีกว่าคือการใช้มัณฑนากรแทนการเขียนฟังก์ชั่นเสื้อคลุมด้วยมือ โดยเฉพาะอย่างยิ่งเมื่อคุณมีฟังก์ชั่นมากมายในการตกแต่งแผนที่มัณฑนากรจะประหยัดเวลาของคุณโดยหลีกเลี่ยงการเขียนกระดาษห่อสำหรับทุกฟังก์ชั่น โดยปกติแล้วฟังก์ชั่นการตกแต่งไม่สามารถเลือกได้ แต่เราอาจใช้functoolsเพื่อหลีกเลี่ยง disscusions เพิ่มเติมสามารถพบได้ที่นี่

นี่คือตัวอย่าง

def unpack_args(func):
    from functools import wraps
    @wraps(func)
    def wrapper(args):
        if isinstance(args, dict):
            return func(**args)
        else:
            return func(*args)
    return wrapper

@unpack_args
def func(x, y):
    return x + y

จากนั้นคุณสามารถแมปกับอาร์กิวเมนต์ที่มีการซิป

np, xlist, ylist = 2, range(10), range(10)
pool = Pool(np)
res = pool.map(func, zip(xlist, ylist))
pool.close()
pool.join()

แน่นอนคุณอาจใช้Pool.starmapใน Python 3 (> = 3.3) ตามที่ระบุไว้ในคำตอบอื่น ๆ เสมอ


ผลลัพธ์ไม่เป็นไปตามที่คาดไว้: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] ฉันคาดหวัง: [0,1,2,3,4,5,6,7,8, 9,1,2,3,4,5,6,7,8,9,10,2,3,4,5,6,7,8,9,10,11 ...
Tedo Vrbanec

@TedoVrbanec ผลลัพธ์ควรเป็น [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] หากคุณต้องการในภายหลังหนึ่งคุณอาจจะใช้แทนitertools.product zip
Syrtis Major

4

อีกวิธีหนึ่งคือส่งรายการของรายการไปยังรูทีน one-อาร์กิวเมนต์:

import os
from multiprocessing import Pool

def task(args):
    print "PID =", os.getpid(), ", arg1 =", args[0], ", arg2 =", args[1]

pool = Pool()

pool.map(task, [
        [1,2],
        [3,4],
        [5,6],
        [7,8]
    ])

หนึ่งสามารถสร้างรายการของข้อโต้แย้งด้วยวิธีที่ชื่นชอบ


นี่เป็นวิธีที่ง่าย แต่คุณต้องเปลี่ยนฟังก์ชั่นดั้งเดิมของคุณ ยิ่งไปกว่านั้นบางครั้งก็เรียกฟังก์ชั่นของผู้อื่นซึ่งอาจไม่สามารถแก้ไขได้
WeizhongTu

ฉันจะบอกว่านี่ติดกับ Python Zen ควรมีวิธีที่ชัดเจนเพียงวิธีเดียวเท่านั้น หากบังเอิญคุณเป็นผู้แต่งฟังก์ชั่นการโทรคุณควรใช้วิธีนี้สำหรับกรณีอื่น ๆ ที่เราสามารถใช้วิธีการของ imotai
nehem

ตัวเลือกของฉันคือใช้สิ่งอันดับจากนั้นก็แกะพวกเขาเป็นสิ่งแรกในบรรทัดแรกทันที
nehem

3

นี่เป็นอีกวิธีในการทำ IMHO นั้นง่ายและสง่างามกว่าคำตอบอื่น ๆ ที่มีให้

โปรแกรมนี้มีฟังก์ชั่นที่ใช้สองพารามิเตอร์พิมพ์ออกมาและพิมพ์ผลรวม:

import multiprocessing

def main():

    with multiprocessing.Pool(10) as pool:
        params = [ (2, 2), (3, 3), (4, 4) ]
        pool.starmap(printSum, params)
    # end with

# end function

def printSum(num1, num2):
    mySum = num1 + num2
    print('num1 = ' + str(num1) + ', num2 = ' + str(num2) + ', sum = ' + str(mySum))
# end function

if __name__ == '__main__':
    main()

ผลลัพธ์คือ:

num1 = 2, num2 = 2, sum = 4
num1 = 3, num2 = 3, sum = 6
num1 = 4, num2 = 4, sum = 8

ดูเอกสารหลามสำหรับข้อมูลเพิ่มเติม:

https://docs.python.org/3/library/multiprocessing.html#module-multiprocessing.pool

โดยเฉพาะให้แน่ใจว่าได้ตรวจสอบstarmapฟังก์ชั่น

ฉันใช้ Python 3.6 ฉันไม่แน่ใจว่าจะทำงานกับ Python เวอร์ชันเก่ากว่าได้หรือไม่

ทำไมไม่มีตัวอย่างตรงๆเช่นนี้ในเอกสารฉันไม่แน่ใจ


2

จาก python 3.4.4 คุณสามารถใช้ multiprocessing.get_context () เพื่อรับวัตถุบริบทเพื่อใช้วิธีการเริ่มต้นหลายวิธี:

import multiprocessing as mp

def foo(q, h, w):
    q.put(h + ' ' + w)
    print(h + ' ' + w)

if __name__ == '__main__':
    ctx = mp.get_context('spawn')
    q = ctx.Queue()
    p = ctx.Process(target=foo, args=(q,'hello', 'world'))
    p.start()
    print(q.get())
    p.join()

หรือคุณเพียงแค่แทนที่

pool.map(harvester(text,case),case, 1)

โดย:

pool.apply_async(harvester(text,case),case, 1)

2

มีคำตอบมากมายที่นี่ แต่ดูเหมือนจะไม่มีรหัสใดที่รองรับ Python 2/3 ที่สามารถใช้งานได้กับทุกรุ่น หากคุณต้องการให้โค้ดของคุณใช้งานได้จะเป็นการทำงานกับ Python เวอร์ชันใดเวอร์ชันหนึ่ง:

# For python 2/3 compatibility, define pool context manager
# to support the 'with' statement in Python 2
if sys.version_info[0] == 2:
    from contextlib import contextmanager
    @contextmanager
    def multiprocessing_context(*args, **kwargs):
        pool = multiprocessing.Pool(*args, **kwargs)
        yield pool
        pool.terminate()
else:
    multiprocessing_context = multiprocessing.Pool

หลังจากนั้นคุณสามารถใช้การประมวลผลหลายทางตามปกติของ Python 3 ได้ตามต้องการ ตัวอย่างเช่น:

def _function_to_run_for_each(x):
       return x.lower()
with multiprocessing_context(processes=3) as pool:
    results = pool.map(_function_to_run_for_each, ['Bob', 'Sue', 'Tim'])    print(results)

จะทำงานใน Python 2 หรือ Python 3


1

ในเอกสารประกอบอย่างเป็นทางการระบุว่าสนับสนุนอาร์กิวเมนต์ที่ทำซ้ำได้เพียงข้อเดียวเท่านั้น ฉันต้องการใช้ Apply_async ในกรณีเช่นนี้ ในกรณีของคุณฉันจะทำ:

from multiprocessing import Process, Pool, Manager

text = "test"
def harvester(text, case, q = None):
 X = case[0]
 res = text+ str(X)
 if q:
  q.put(res)
 return res


def block_until(q, results_queue, until_counter=0):
 i = 0
 while i < until_counter:
  results_queue.put(q.get())
  i+=1

if __name__ == '__main__':
 pool = multiprocessing.Pool(processes=6)
 case = RAW_DATASET
 m = Manager()
 q = m.Queue()
 results_queue = m.Queue() # when it completes results will reside in this queue
 blocking_process = Process(block_until, (q, results_queue, len(case)))
 blocking_process.start()
 for c in case:
  try:
   res = pool.apply_async(harvester, (text, case, q = None))
   res.get(timeout=0.1)
  except:
   pass
 blocking_process.join()

1
text = "test"

def unpack(args):
    return args[0](*args[1:])

def harvester(text, case):
    X = case[0]
    text+ str(X)

if __name__ == '__main__':
    pool = multiprocessing.Pool(processes=6)
    case = RAW_DATASET
    # args is a list of tuples 
    # with the function to execute as the first item in each tuple
    args = [(harvester, text, c) for c in case]
    # doing it this way, we can pass any function
    # and we don't need to define a wrapper for each different function
    # if we need to use more than one
    pool.map(unpack, args)
    pool.close()
    pool.join()

1

นี่คือตัวอย่างของชุดคำสั่งที่ฉันใช้เพื่อส่งอาร์กิวเมนต์หลายตัวไปยังฟังก์ชันหนึ่งอาร์กิวเมนต์ที่ใช้ในpool.imap fork:

from multiprocessing import Pool

# Wrapper of the function to map:
class makefun:
    def __init__(self, var2):
        self.var2 = var2
    def fun(self, i):
        var2 = self.var2
        return var1[i] + var2

# Couple of variables for the example:
var1 = [1, 2, 3, 5, 6, 7, 8]
var2 = [9, 10, 11, 12]

# Open the pool:
pool = Pool(processes=2)

# Wrapper loop
for j in range(len(var2)):
    # Obtain the function to map
    pool_fun = makefun(var2[j]).fun

    # Fork loop
    for i, value in enumerate(pool.imap(pool_fun, range(len(var1))), 0):
        print(var1[i], '+' ,var2[j], '=', value)

# Close the pool
pool.close()

-3

สำหรับ python2 คุณสามารถใช้เคล็ดลับนี้ได้

def fun(a,b):
    return a+b

pool = multiprocessing.Pool(processes=6)
b=233
pool.map(lambda x:fun(x,b),range(1000))

ทำไม b = 233 เอาชนะจุดประสงค์ของคำถาม
ราวกับ - ถ้า
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.