การประมวลผลหลายตัวพูล: เมื่อใดที่จะใช้ใช้ Apply_async หรือแผนที่


คำตอบ:


424

ย้อนกลับไปในยุคเก่าของ Python เพื่อเรียกใช้ฟังก์ชั่นที่มีอากิวเมนต์โดยพลการคุณจะต้องใช้apply:

apply(f,args,kwargs)

applyยังคงมีอยู่ใน Python2.7 แม้ว่าจะไม่ใช่ใน Python3 และโดยทั่วไปจะไม่ใช้อีกต่อไป ปัจจุบัน

f(*args,**kwargs)

เป็นที่ต้องการ multiprocessing.Poolโมดูลพยายามที่จะให้อินเตอร์เฟซที่คล้ายกัน

Pool.applyเหมือนกับ Python applyยกเว้นว่าการเรียกใช้ฟังก์ชันจะดำเนินการในกระบวนการแยกต่างหาก Pool.applyบล็อกจนกว่าฟังก์ชันจะเสร็จสมบูรณ์

Pool.apply_asyncก็เหมือนกับ Python ในตัวapplyยกเว้นการโทรกลับทันทีแทนที่จะรอผลลัพธ์ AsyncResultวัตถุจะถูกส่งกลับ คุณเรียกget()วิธีการเพื่อดึงผลลัพธ์ของการเรียกใช้ฟังก์ชัน get()วิธีการบล็อกจนกว่าการทำงานจะเสร็จสมบูรณ์ ดังนั้นจะเทียบเท่ากับpool.apply(func, args, kwargs)pool.apply_async(func, args, kwargs).get()

ในทางตรงกันข้ามกับPool.applyที่Pool.apply_asyncวิธีการนี้ยังมีการเรียกกลับซึ่งถ้าจัดจะถูกเรียกเมื่อฟังก์ชั่นเสร็จสมบูรณ์ สามารถใช้แทนการโทรget()ได้

ตัวอย่างเช่น:

import multiprocessing as mp
import time

def foo_pool(x):
    time.sleep(2)
    return x*x

result_list = []
def log_result(result):
    # This is called whenever foo_pool(i) returns a result.
    # result_list is modified only by the main process, not the pool workers.
    result_list.append(result)

def apply_async_with_callback():
    pool = mp.Pool()
    for i in range(10):
        pool.apply_async(foo_pool, args = (i, ), callback = log_result)
    pool.close()
    pool.join()
    print(result_list)

if __name__ == '__main__':
    apply_async_with_callback()

อาจให้ผลลัพธ์เช่น

[1, 0, 4, 9, 25, 16, 49, 36, 81, 64]

สังเกตpool.mapว่าคำสั่งของผลลัพธ์อาจไม่สอดคล้องกับลำดับการpool.apply_asyncโทร


ดังนั้นถ้าคุณจำเป็นต้องเรียกใช้ฟังก์ชั่นในกระบวนการแยก แต่ต้องการกระบวนการปัจจุบันเพื่อบล็อกPool.applyจนผลตอบแทนที่ฟังก์ชั่นการใช้งาน ชอบPool.apply, Pool.mapบล็อกจนกว่าผลที่สมบูรณ์จะถูกส่งกลับ

Pool.apply_asyncถ้าคุณต้องการที่สระว่ายน้ำของผู้ปฏิบัติงานกระบวนการที่จะดำเนินการเรียกฟังก์ชันหลายแบบไม่พร้อมใช้งาน การสั่งซื้อPool.apply_asyncของผลไม่รับประกันว่าจะเป็นเช่นเดียวกับคำสั่งของสายไปยัง

โปรดสังเกตว่าคุณสามารถโทรไปยังฟังก์ชั่นต่าง ๆด้วยPool.apply_async(ไม่จำเป็นต้องใช้ฟังก์ชั่นเดียวกันทุกสาย)

ในทางตรงกันข้ามPool.mapใช้ฟังก์ชันเดียวกันกับอาร์กิวเมนต์จำนวนมาก อย่างไรก็ตามPool.apply_asyncผลลัพธ์จะถูกส่งคืนในลำดับที่สอดคล้องกับลำดับของอาร์กิวเมนต์


11
ควรจะมีมาif __name__=="__main__"ก่อนapply_async_with_callback()ใน Windows?
jfs

3
ขอบคุณมาก. แล้ว map_async ล่ะ
Phyo Arkar Lwin

38
มองภายในmultiprocessing / pool.pyและคุณจะเห็นว่าเทียบเท่ากับPool.map(func,iterable) Pool.map_async(func,iterable).get()ดังนั้นความสัมพันธ์ระหว่างPool.mapและPool.map_asyncเป็นแบบเดียวกับที่และPool.apply คำสั่งกลับทันทีขณะที่ไม่ใช่คำสั่งปิดกั้น คำสั่งยังมีการติดต่อกลับ Pool.apply_asyncasyncasyncasync
unutbu

7
การตัดสินใจระหว่างการใช้Pool.mapและPool.applyคล้ายกับการตัดสินใจว่าจะใช้เมื่อใดmapหรือapplyใน Python คุณเพียงแค่ใช้เครื่องมือที่เหมาะกับงาน การตัดสินใจระหว่างการใช้asyncและไม่ใช่asyncเวอร์ชันนั้นขึ้นอยู่กับว่าคุณต้องการให้การโทรเพื่อบล็อกกระบวนการปัจจุบันและ / หรือถ้าคุณต้องการใช้การโทรกลับ
unutbu

6
@fullPockets: ใช่ การเรียกแต่ละครั้งเพื่อapply_asyncส่งคืนApplyResultวัตถุ โทรที่ApplyResult's getวิธีการจะกลับมาส่งคืนค่าฟังก์ชั่นที่เกี่ยวข้อง (หรือเพิ่มmp.TimeoutErrorถ้าโทรออกครั้ง.) ดังนั้นถ้าคุณใส่ApplyResultในรายการสั่งซื้อแล้วโทรของพวกเขาgetวิธีการจะให้ผลลัพธ์ในลำดับเดียวกัน คุณสามารถใช้pool.mapในสถานการณ์นี้ได้อย่างไรก็ตาม
unutbu

75

เกี่ยวกับapplyvs map:

pool.apply(f, args): fถูกดำเนินการในหนึ่งในพนักงานของพูลเท่านั้น f(args)ดังนั้นหนึ่งของกระบวนการในสระว่ายน้ำจะทำงาน

pool.map(f, iterable): วิธีนี้สับ iterable เป็นจำนวนชิ้นซึ่งส่งไปยังกลุ่มกระบวนการเป็นงานแยกต่างหาก ดังนั้นคุณใช้ประโยชน์จากกระบวนการทั้งหมดในกลุ่ม


4
เกิดอะไรขึ้นถ้าเครื่องกำเนิดไฟฟ้าทำ
ซ้ำได้

อืม ... เป็นคำถามที่ดี บอกตามตรงฉันไม่เคยใช้พูลกับเครื่องกำเนิดไฟฟ้าเลย แต่เธรดนี้อาจมีประโยชน์: stackoverflow.com/questions/5318936/…
kakhkAtion

@kakhkAtion เกี่ยวกับการนำไปใช้หากมีเพียงหนึ่งในผู้ปฏิบัติงานที่ทำงานส่วนที่เหลือของคนงานทำอะไร? ฉันต้องโทรหาใช้หลายครั้งเพื่อให้คนงานที่เหลือปฏิบัติงานหรือไม่?
Moondra

3
จริง ดูที่ pool.apply_async ด้วยถ้าคุณต้องการคนงานอาหารกลางวันแบบอะซิงโครนัส "pool_apply บล็อกจนกว่าผลลัพธ์จะพร้อมดังนั้น Apply_async () จึงเหมาะสำหรับการทำงานแบบขนาน"
kakhkAtion

1
จะเกิดอะไรขึ้นเมื่อฉันมี 4 กระบวนการ แต่เรียกว่าapply_async()8 ครั้ง มันจะจัดการกับคิวโดยอัตโนมัติหรือไม่?
Saravanabalagi Ramachandran

31

นี่คือภาพรวมในรูปแบบตารางในเพื่อแสดงให้เห็นความแตกต่างระหว่างPool.apply, Pool.apply_async, และPool.map Pool.map_asyncเมื่อเลือกอย่างใดอย่างหนึ่งคุณจะต้องคำนึงถึงหลายอย่างพร้อมกันบล็อกและการสั่งซื้อ:

                  | Multi-args   Concurrence    Blocking     Ordered-results
---------------------------------------------------------------------
Pool.map          | no           yes            yes          yes
Pool.map_async    | no           yes            no           yes
Pool.apply        | yes          no             yes          no
Pool.apply_async  | yes          yes            no           no
Pool.starmap      | yes          yes            yes          yes
Pool.starmap_async| yes          yes            no           no

หมายเหตุ:

  • Pool.imapand Pool.imap_async- รุ่นแผนที่ที่อ่อนแอกว่าและ map_async

  • Pool.starmap วิธีการคล้ายกันมากกับวิธีการแผนที่นอกจากจะยอมรับการขัดแย้งหลาย

  • Asyncวิธีการส่งกระบวนการทั้งหมดในครั้งเดียวและดึงผลลัพธ์เมื่อพวกเขาเสร็จสิ้น ใช้วิธีรับเพื่อรับผลลัพธ์

  • Pool.map(หรือPool.apply) วิธีการคล้ายกับแผนที่ในตัวของ Python (หรือใช้) พวกเขาบล็อกกระบวนการหลักจนกว่ากระบวนการทั้งหมดจะเสร็จสมบูรณ์และส่งคืนผลลัพธ์

ตัวอย่าง:

แผนที่

ถูกเรียกสำหรับรายการของงานในครั้งเดียว

results = pool.map(func, [1, 2, 3])

ใช้

สามารถเรียกได้เพียงหนึ่งงานเท่านั้น

for x, y in [[1, 1], [2, 2]]:
    results.append(pool.apply(func, (x, y)))

def collect_result(result):
    results.append(result)

map_async

ถูกเรียกสำหรับรายการของงานในครั้งเดียว

pool.map_async(func, jobs, callback=collect_result)

apply_async

สามารถเรียกได้หนึ่งงานเท่านั้นและเรียกใช้งานในพื้นหลังแบบขนาน

for x, y in [[1, 1], [2, 2]]:
    pool.apply_async(worker, (x, y), callback=collect_result)

starmap

เป็นตัวแปรpool.mapที่สนับสนุนอาร์กิวเมนต์หลายตัว

pool.starmap(func, [(1, 1), (2, 1), (3, 1)])

starmap_async

การรวมกันของ starmap () และ map_async () ที่วนซ้ำ iterable ของ iterables และการโทร func ด้วยการทำซ้ำ iterables ส่งคืนวัตถุผลลัพธ์

pool.starmap_async(calculate_worker, [(1, 1), (2, 1), (3, 1)], callback=collect_result)

อ้างอิง:

ค้นหาเอกสารฉบับสมบูรณ์ได้ที่นี่: https://docs.python.org/3/library/multiprocessing.html


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