การประมวลผลหลายขั้นตอนเทียบกับมัลติเธรดเทียบกับ asyncio ใน Python 3


123

ฉันพบว่าในหลาม 3.4 มีห้องสมุดที่แตกต่างกันไม่กี่ multiprocessing / เกลียว: multiprocessing VS เกลียว VS asyncio

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


1
บางทีฉันอาจจะโง่เกินไปที่ AsyncIOช่วย
Martin Thoma

คำตอบ:


86

มีไว้เพื่อวัตถุประสงค์และ / หรือข้อกำหนดที่แตกต่างกัน (เล็กน้อย) CPython (การใช้งาน Python แบบ mainline โดยทั่วไป) ยังคงมีการล็อคตัวแปลส่วนกลางดังนั้นแอปพลิเคชันแบบหลายเธรด (วิธีมาตรฐานในการใช้การประมวลผลแบบขนานในปัจจุบัน) จึงไม่เหมาะสม นั่นเป็นเหตุผลที่multiprocessing อาจthreadingจะต้องการมากกว่า แต่ไม่ใช่ว่าปัญหาทุกอย่างจะแยกออกเป็นส่วน ๆ [เกือบจะเป็นอิสระ] ได้อย่างมีประสิทธิภาพดังนั้นจึงอาจมีความจำเป็นในการสื่อสารระหว่างกระบวนการที่หนักหน่วง นั่นเป็นเหตุผลที่multiprocessingอาจไม่เป็นที่ต้องการthreadingโดยทั่วไป

asyncio(เทคนิคนี้มีให้ใช้งานไม่เพียง แต่ใน Python เท่านั้นภาษาและ / หรือเฟรมเวิร์กอื่น ๆ ก็มีเช่นBoost.ASIO ) เป็นวิธีการจัดการกับการดำเนินการ I / O จำนวนมากจากแหล่งข้อมูลหลายแหล่งพร้อมกันโดยไม่จำเป็นต้องใช้การประมวลผลโค้ดแบบขนาน . ดังนั้นจึงเป็นเพียงวิธีแก้ปัญหา (เป็นวิธีที่ดีจริงๆ!) สำหรับงานเฉพาะไม่ใช่สำหรับการประมวลผลแบบขนานโดยทั่วไป


7
สังเกตว่าแม้ว่าทั้งสามอาจไม่บรรลุความเท่าเทียมกัน แต่พวกเขาก็สามารถทำงานพร้อมกัน (ไม่ปิดกั้น) ได้
sargas

78

TL; ดร

การเลือกที่ถูกต้อง:

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

if io_bound:
    if io_very_slow:
        print("Use Asyncio")
    else:
        print("Use Threads")
else:
    print("Multi Processing")
  • CPU Bound => หลายการประมวลผล
  • I / O Bound, Fast I / O, จำนวนการเชื่อมต่อที่ จำกัด => Multi Threading
  • I / O Bound, Slow I / O, การเชื่อมต่อจำนวนมาก => Asyncio

ข้อมูลอ้างอิง


[ หมายเหตุ ]:

  • หากคุณมีวิธีการโทรแบบยาว (เช่นวิธีการที่มีเวลาสลีปหรือ I / O ที่ขี้เกียจ) ตัวเลือกที่ดีที่สุดคือวิธี asyncio , TwistedหรือTornado (วิธีการโครูทีน) ซึ่งทำงานกับเธรดเดียวเป็นแบบพร้อมกัน
  • asyncioทำงานบนPython3.4และใหม่กว่า
  • TornadoและTwistedพร้อมแล้วตั้งแต่Python2.7
  • uvloopเป็นasyncioลูปเหตุการณ์ที่เร็วมาก( uvloopทำให้asyncioเร็วขึ้น2-4เท่า)

[อัพเดท (2019)]:

  • Japranto ( GitHub )เป็นเซิร์ฟเวอร์ HTTP วิธี pipeline อย่างรวดเร็วบนพื้นฐานของuvloop

ดังนั้นถ้าฉันมีรายการ url ที่จะขอใช้Asyncioดีกว่าไหม
mingchau

1
@mingchau ใช่ แต่โปรดจำไว้ว่าคุณสามารถใช้asyncioเมื่อคุณใช้จากฟังก์ชันที่รอคอยได้requestไลบรารีไม่ใช่วิธีการที่รอคอยได้แทนที่จะใช้วิธีนี้เช่นaiohttpไลบรารีหรือคำขอ asyncเป็นต้น
Benyamin Jafari

โปรดขยาย slowIO และ fastIO เพื่อไปยังมัลติเธรดหรือ asyncio>?
qrtLs

1
คุณช่วยแนะนำได้ไหมว่า io_very_slow คืออะไร
ตัวแปร

1
@variable I / O bound หมายถึงโปรแกรมของคุณใช้เวลาส่วนใหญ่ในการพูดคุยกับอุปกรณ์ที่ทำงานช้าเช่นการเชื่อมต่อเครือข่ายฮาร์ดไดรฟ์เครื่องพิมพ์หรือการวนรอบเหตุการณ์ด้วยเวลาพักเครื่อง ดังนั้นในโหมดการบล็อกคุณสามารถเลือกระหว่างเธรดหรือ asyncio และหากส่วนขอบเขตของคุณช้ามากการทำงานหลายอย่างแบบร่วมมือกัน (asyncio) เป็นทางเลือกที่ดีกว่า (เช่นหลีกเลี่ยงการอดอยากทรัพยากรการล็อกการตายและสภาพการแข่งขัน)
Benyamin Jafari

10

นี่คือแนวคิดพื้นฐาน:

เป็นIO -BOUND หรือไม่? ---------> ใช้asyncio

มันเป็นCPU -HEAVY หรือไม่? -----> ใช้multiprocessing

อย่างอื่น? ----------------------> ใช้threading

โดยพื้นฐานแล้วให้ยึดกับเธรดเว้นแต่คุณจะมีปัญหา IO / CPU


5

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

ในเธรด (หลาย)คุณไม่ต้องการซีพียูหลายตัว ลองนึกภาพโปรแกรมที่ส่งคำขอ HTTP จำนวนมากไปยังเว็บ หากคุณใช้โปรแกรมเธรดเดียวโปรแกรมจะหยุดการดำเนินการ (บล็อก) ในแต่ละคำขอรอการตอบกลับจากนั้นดำเนินการต่อเมื่อได้รับการตอบกลับ ปัญหาคือ CPU ของคุณไม่ทำงานจริงๆในขณะที่รอให้เซิร์ฟเวอร์ภายนอกทำงาน ในระหว่างนี้มันสามารถทำงานที่มีประโยชน์ได้จริง! การแก้ไขคือการใช้เธรด - คุณสามารถสร้างได้หลายชุดโดยแต่ละชุดมีหน้าที่ในการขอเนื้อหาบางส่วนจากเว็บ สิ่งที่ดีเกี่ยวกับเธรดคือแม้ว่าจะทำงานบน CPU ตัวเดียว แต่ CPU จะ "หยุด" การทำงานของเธรดหนึ่งเป็นครั้งคราวและข้ามไปดำเนินการกับเธรดอื่น (เรียกว่าการสลับบริบทและจะเกิดขึ้นตลอดเวลาโดยไม่ได้กำหนด ช่วงเวลา) - ใช้เธรด

asyncioเป็นหลักเกลียวที่ไม่ได้เป็น CPU แต่คุณเป็นโปรแกรมเมอร์ (หรือจริงใบสมัครของคุณ) ตัดสินใจที่ไหนและเมื่อไม่เปลี่ยนบริบทเกิดขึ้น ใน Python คุณใช้awaitคีย์เวิร์ดเพื่อระงับการทำงานของโครูทีนของคุณ (กำหนดโดยใช้asyncคีย์เวิร์ด)


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

ไม่แน่ใจว่าเข้าใจคำถามหรือไม่ เกี่ยวกับว่าคุณควรใช้หลายคอร์เมื่อการตอบสนองเร็วขึ้นหรือไม่? หากเป็นเช่นนั้นก็ขึ้นอยู่กับว่าการตอบสนองนั้นเร็วเพียงใดและคุณใช้เวลารอนานแค่ไหนเทียบกับการใช้ CPU หากคุณใช้เวลาส่วนใหญ่ในการทำงานที่ต้องใช้ CPU เป็นจำนวนมากการแจกจ่ายผ่านหลายคอร์จะเป็นประโยชน์ (ถ้าเป็นไปได้) และหากเกิดคำถามว่าระบบจะเปลี่ยนไปใช้การประมวลผลแบบขนานโดยธรรมชาติหรือไม่หลังจาก "ตระหนัก" ว่างานของมันถูกเชื่อมต่อกับ CPU - ฉันไม่คิดอย่างนั้น - โดยปกติคุณต้องบอกอย่างชัดเจนว่าจะทำเช่นนั้น
Tomasz Bartkowiak

ฉันกำลังคิดถึงแอปพลิเคชัน chatbot ซึ่งข้อความ chatbot โดยผู้ใช้จะถูกส่งไปยังเซิร์ฟเวอร์และเซิร์ฟเวอร์จะส่งการตอบกลับโดยใช้คำขอ POST? คุณคิดว่านี่เป็นงานที่ต้องใช้ CPU มากขึ้นหรือไม่เนื่องจากการตอบกลับที่ส่งและรับสามารถเป็น json ได้ แต่ฉันสงสัยว่าจะเกิดอะไรขึ้นถ้าผู้ใช้ใช้เวลาในการพิมพ์คำตอบนี่เป็นตัวอย่างของ I / O ที่ช้าหรือไม่ (ผู้ใช้ส่งการตอบกลับล่าช้า)
aspiring1
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.