Concurrent.futures vs Multiprocessing ใน Python 3


148

Python 3.2 เปิดตัวConcurrent Futuresซึ่งเป็นส่วนผสมขั้นสูงของโมดูลการทำเกลียวและมัลติโพรเซสซิ่งที่เก่ากว่า

อะไรคือข้อดีและข้อเสียของการใช้สิ่งนี้สำหรับงานที่ผูกกับ CPU ผ่านโมดูลมัลติโปรเซสเซอร์ที่เก่ากว่า?

บทความนี้แสดงให้เห็นว่าพวกเขาทำงานได้ง่ายขึ้น - เป็นอย่างนั้นหรือ

คำตอบ:


145

ฉันจะไม่เรียกconcurrent.futures"ขั้นสูง" เพิ่มเติม - เป็นอินเทอร์เฟซที่เรียบง่ายซึ่งทำงานได้เหมือนกันโดยไม่คำนึงว่าคุณจะใช้หลายเธรดหรือหลายกระบวนการเป็นกลไกการขนานแบบขนาน

ดังนั้นเหมือนแทบทุกกรณีของ "อินเตอร์เฟซที่เรียบง่าย" มากเหมือนกันไม่ชอบการค้ามีส่วนร่วม: มันมีเส้นโค้งการเรียนรู้ตื้นส่วนใหญ่เพียงเพราะมีมากน้อยลงที่จะต้องเรียนรู้; แต่เนื่องจากมีตัวเลือกน้อยลงในที่สุดจึงอาจทำให้คุณไม่พอใจที่อินเทอร์เฟซที่สมบูรณ์ยิ่งขึ้น

ตราบใดที่ภาระผูกพันของ CPU ดำเนินต่อไปนั่นก็เป็นวิธีที่ไม่สามารถระบุความหมายได้มากเกินไป สำหรับงานที่ผูกกับ CPU ภายใต้ CPython คุณต้องมีหลายกระบวนการแทนที่จะใช้หลายเธรดเพื่อให้มีโอกาสในการเพิ่มความเร็ว แต่ความเร็วที่คุณได้รับนั้นขึ้นอยู่กับรายละเอียดของฮาร์ดแวร์ระบบปฏิบัติการของคุณและโดยเฉพาะอย่างยิ่งกับการสื่อสารระหว่างกระบวนการที่คุณต้องการ ภายใต้หน้าปกกลเม็ดการปรับเทียบระหว่างกระบวนการทั้งหมดนั้นอาศัยหลักการพื้นฐานของระบบปฏิบัติการเดียวกันนั่นคือ API ระดับสูงที่คุณใช้เพื่อให้ได้มาซึ่งสิ่งเหล่านี้ไม่ใช่ปัจจัยหลักในความเร็วของบรรทัดล่าง

แก้ไข: ตัวอย่าง

นี่คือรหัสสุดท้ายที่แสดงในบทความที่คุณอ้างถึง แต่ฉันกำลังเพิ่มคำสั่งการนำเข้าที่จำเป็นเพื่อให้ใช้ได้:

from concurrent.futures import ProcessPoolExecutor
def pool_factorizer_map(nums, nprocs):
    # Let the executor divide the work among processes by using 'map'.
    with ProcessPoolExecutor(max_workers=nprocs) as executor:
        return {num:factors for num, factors in
                                zip(nums,
                                    executor.map(factorize_naive, nums))}

นี่คือสิ่งเดียวกันโดยใช้multiprocessingแทน:

import multiprocessing as mp
def mp_factorizer_map(nums, nprocs):
    with mp.Pool(nprocs) as pool:
        return {num:factors for num, factors in
                                zip(nums,
                                    pool.map(factorize_naive, nums))}

โปรดทราบว่ามีการเพิ่มความสามารถในการใช้multiprocessing.Poolวัตถุเป็นตัวจัดการบริบทใน Python 3.3

อันไหนง่ายกว่าที่จะทำงานกับ? LOL ;-) พวกมันเหมือนกันหมด

หนึ่งความแตกต่างก็คือPoolการสนับสนุนรูปแบบต่างๆมากมายในการทำสิ่งที่คุณอาจไม่ตระหนักถึงวิธีการที่ง่ายก็สามารถจะจนกว่าคุณจะได้ปีนขึ้นไปค่อนข้างวิธีขึ้นโค้งการเรียนรู้

อีกครั้งวิธีที่ต่างกันทั้งหมดนั้นคือทั้งจุดแข็งและจุดอ่อน มันเป็นจุดแข็งเพราะความยืดหยุ่นอาจจำเป็นในบางสถานการณ์ พวกเขาเป็นจุดอ่อนเพราะ "ควรมีวิธีที่ชัดเจนเพียงวิธีเดียวเท่านั้น" โครงการที่ติดอยู่เฉพาะ (ถ้าเป็นไปได้) concurrent.futuresอาจจะง่ายต่อการดูแลรักษาในระยะยาวเนื่องจากการขาดความแปลกใหม่ที่ไม่มีเหตุผลในการใช้ API ขั้นต่ำของมัน


20
"คุณต้องมีหลายกระบวนการแทนที่จะใช้หลายเธรดเพื่อให้มีโอกาสในการรับความเร็ว"รุนแรงเกินไป ถ้าความเร็วเป็นสิ่งสำคัญ รหัสอาจใช้ไลบรารี C อยู่แล้วดังนั้นจึงสามารถเผยแพร่ GIL เช่น regex, lxml, numpy
jfs

4
@JFSebastian ขอบคุณสำหรับการเพิ่ม - บางทีฉันควรจะพูดว่า "ภายใต้บริสุทธิ์ CPython" แต่ฉันเกรงว่าจะไม่มีวิธีการอธิบายความจริงที่นี่โดยไม่พูดถึง GIL
Tim Peters

2
และมันก็คุ้มค่าที่จะกล่าวถึงว่าเธรดอาจมีประโยชน์เป็นพิเศษและเพียงพอเมื่อมีการดำเนินการที่มี IO ยาว
kotrfa

9
@TimPeters ในบางวิธีProcessPoolExecutorจริงมีตัวเลือกมากขึ้นกว่าPoolเพราะProcessPoolExecutor.submitผลตอบแทนFutureกรณีที่อนุญาตให้มีการยกเลิก ( cancel) ตรวจสอบซึ่งข้อยกเว้นได้รับการเลี้ยงดู ( exception) และแบบไดนามิกเพิ่มโทรกลับจะถูกเรียกว่าเมื่อเสร็จสิ้น ( add_done_callback) ไม่มีคุณสมบัติเหล่านี้จะสามารถใช้ได้กับกรณีที่ส่งกลับโดยAsyncResult Pool.apply_asyncในรูปแบบอื่น ๆ ที่Poolมีตัวเลือกมากขึ้นเนื่องจากการinitializer/ initargs, maxtasksperchildและcontextในPool.__init__และวิธีการอื่น ๆ เปิดเผยโดยPoolอินสแตนซ์
สูงสุด

2
@ max แน่นอน แต่โปรดทราบว่าคำถามไม่ได้เกี่ยวกับPoolมันเป็นเกี่ยวกับโมดูล Poolเป็นส่วนเล็ก ๆ ของสิ่งที่อยู่ในและเพื่อให้ห่างไกลลงไปในเอกสารที่ใช้ในขณะที่สำหรับคนที่จะตระหนักก็ยังมีอยู่ในmultiprocessing multiprocessingคำตอบนี้เน้นที่Poolเพราะนั่นคือทั้งหมดที่บทความ OP เชื่อมโยงกับการใช้และนั่นcfคือ "ง่ายกว่าที่จะทำงานกับ" เพียงแค่ไม่เป็นความจริงเกี่ยวกับสิ่งที่กล่าวถึงในบทความ นอกเหนือจากนั้นcf's as_completed()ยังสามารถเป็นประโยชน์มาก
Tim Peters
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.