multiprocessing.Pool: map_async และ imap ต่างกันอย่างไร


184

ฉันพยายามที่จะเรียนรู้วิธีการใช้งูใหญ่multiprocessingแพคเกจ แต่ผมไม่เข้าใจความแตกต่างระหว่างและmap_async imapฉันสังเกตเห็นว่าทั้งสองmap_asyncและimapถูกดำเนินการแบบอะซิงโครนัส ดังนั้นเมื่อไรฉันจึงควรใช้อันอื่น และฉันจะดึงผลลัพธ์ที่ส่งคืนมาได้map_asyncอย่างไร?

ฉันควรใช้สิ่งนี้หรือไม่?

def test():
    result = pool.map_async()
    pool.close()
    pool.join()
    return result.get()

result=test()
for i in result:
    print i

คำตอบ:


492

มีความแตกต่างที่สำคัญสองอย่างระหว่างimap/ imap_unorderedและmap/ map_async:

  1. วิธีที่พวกเขาบริโภคมันที่คุณผ่านไป
  2. วิธีที่พวกเขาส่งคืนผลลัพธ์ให้คุณ

mapกิน iterable ของคุณโดยการแปลง iterable ไปยังรายการ (สมมติว่ามันไม่ได้เป็นรายการแล้ว), Poolทำลายมันเป็นชิ้นและส่งชิ้นเหล่านั้นไปยังกระบวนการปฏิบัติงานใน การแบ่ง iterable เป็นชิ้นมีประสิทธิภาพดีกว่าการส่งแต่ละไอเท็มใน iterable ระหว่างการประมวลผลทีละรายการ - โดยเฉพาะถ้า iterable มีขนาดใหญ่ อย่างไรก็ตามการเปลี่ยน iterable เป็นรายการเพื่อให้สามารถมีหน่วยความจำสูงมากเนื่องจากรายการทั้งหมดจะต้องเก็บไว้ในหน่วยความจำ

imapไม่เปลี่ยน iterable ที่คุณให้ไว้ในรายการและไม่แบ่งเป็นชิ้น ๆ (ตามค่าเริ่มต้น) มันจะวนซ้ำองค์ประกอบหนึ่งในแต่ละครั้งและส่งพวกเขาไปยังกระบวนการของผู้ปฏิบัติงาน ซึ่งหมายความว่าคุณไม่ต้องใช้หน่วยความจำในการแปลงทั้ง iterable เป็นรายการ แต่ยังหมายถึงประสิทธิภาพจะช้าลงสำหรับ iterables ขนาดใหญ่เนื่องจากการขาดการ chunking อย่างไรก็ตามสิ่งนี้สามารถบรรเทาได้โดยผ่านการchunksizeโต้แย้งมากกว่าค่าเริ่มต้นที่ 1

ข้อแตกต่างที่สำคัญอื่น ๆ ระหว่างimap/ imap_unorderedและmap/ map_asyncคือเมื่อใช้imap/ imap_unorderedคุณสามารถเริ่มรับผลจากคนงานทันทีที่พร้อมแทนที่จะรอให้เสร็จทั้งหมด ด้วยmap_async, AsyncResultจะถูกส่งคืนทันที แต่คุณไม่สามารถดึงผลลัพธ์จากวัตถุนั้นได้จริงจนกว่าจะประมวลผลทั้งหมดแล้วซึ่งจุดที่ส่งกลับรายการเดียวกันกับที่mapทำ ( mapนำไปใช้จริงภายในmap_async(...).get()) ไม่มีทางที่จะได้ผลลัพธ์บางส่วน; คุณมีทั้งผลลัพธ์หรือไม่มีอะไรเลย

imapและimap_unorderedทั้งสองกลับ iterables ทันที ด้วยimapผลลัพธ์จะได้รับจาก iterable ทันทีที่พร้อมในขณะที่ยังคงรักษาการเรียงลำดับของอินพุต iterable ด้วยimap_unorderedผลลัพธ์จะได้รับทันทีที่พร้อมโดยไม่คำนึงถึงลำดับของอินพุตที่ทำซ้ำได้ ดังนั้นสมมติว่าคุณมีสิ่งนี้:

import multiprocessing
import time

def func(x):
    time.sleep(x)
    return x + 2

if __name__ == "__main__":    
    p = multiprocessing.Pool()
    start = time.time()
    for x in p.imap(func, [1,5,3]):
        print("{} (Time elapsed: {}s)".format(x, int(time.time() - start)))

สิ่งนี้จะออก:

3 (Time elapsed: 1s)
7 (Time elapsed: 5s)
5 (Time elapsed: 5s)

หากคุณใช้p.imap_unorderedแทนคุณp.imapจะเห็น:

3 (Time elapsed: 1s)
5 (Time elapsed: 3s)
7 (Time elapsed: 5s)

หากคุณใช้p.mapหรือp.map_async().get()คุณจะเห็น:

3 (Time elapsed: 5s)
7 (Time elapsed: 5s)
5 (Time elapsed: 5s)

ดังนั้นเหตุผลหลักในการใช้imap/ imap_unorderedเกินmap_asyncคือ:

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

1
สิ่งที่เกี่ยวกับการใช้และ Apply_async
Daftary รุนแรง

10
@HarshDaftary applyส่งภารกิจเดียวออกไปยังกระบวนการของผู้ปฏิบัติงานแล้วปิดกั้นจนกว่าจะเสร็จสมบูรณ์ apply_asyncส่งภารกิจเดียวออกไปยังกระบวนการทำงานจากนั้นส่งคืนAsyncResultวัตถุทันทีซึ่งสามารถใช้เพื่อรอให้งานเสร็จสิ้นและรับผลลัพธ์ applyดำเนินการโดยเพียงแค่โทรapply_async(...).get()
dano

51
ที่ชนิดของคำอธิบายที่ควรจะเป็นอย่างเป็นทางการในPoolเอกสารมากกว่าที่มีอยู่หนึ่งที่น่าเบื่อ
นาที

@dano ฉันต้องการเรียกใช้ฟังก์ชั่นในพื้นหลัง แต่ฉันมีข้อ จำกัด ของทรัพยากรบางอย่างและไม่สามารถเรียกใช้ฟังก์ชั่นได้หลายครั้งที่ฉันต้องการและต้องการคิวการประมวลผลเพิ่มเติมของฟังก์ชัน คุณมีความคิดเกี่ยวกับวิธีที่ฉันควรทำอย่างไร ฉันมีคำถามของฉันที่นี่ คุณช่วยลองดูที่คำถามของฉันและดูว่าคุณสามารถให้คำแนะนำกับฉัน (หรือดีกว่าคำตอบ) เกี่ยวกับวิธีที่ฉันควรทำอย่างไร
Amir

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