Asyncio.gather vs asyncio.wait


150

asyncio.gatherและasyncio.waitดูเหมือนว่าจะมีการใช้งานที่คล้ายกัน: ฉันมีหลายสิ่ง async ที่ฉันต้องการที่จะดำเนินการ / รอ (ไม่จำเป็นต้องรอให้เสร็จก่อนที่จะเริ่มต้นต่อไป) พวกเขาใช้ไวยากรณ์ที่แตกต่างกันและแตกต่างกันในรายละเอียดบางอย่าง แต่ดูเหมือนว่าฉันจะไม่รู้สึกไพเราะมากนักที่มี 2 ฟังก์ชั่นที่มีการทับซ้อนกันอย่างมากในการทำงาน ฉันพลาดอะไรไป

คำตอบ:


178

แม้ว่าจะคล้ายกันในกรณีทั่วไป ("เรียกใช้และรับผลลัพธ์สำหรับงานหลายอย่าง") แต่ละฟังก์ชันมีฟังก์ชันการทำงานเฉพาะสำหรับกรณีอื่น ๆ :

asyncio.gather()

ส่งคืนอินสแตนซ์ในอนาคตการอนุญาตให้จัดกลุ่มงานในระดับสูง:

import asyncio
from pprint import pprint

import random


async def coro(tag):
    print(">", tag)
    await asyncio.sleep(random.uniform(1, 3))
    print("<", tag)
    return tag


loop = asyncio.get_event_loop()

group1 = asyncio.gather(*[coro("group 1.{}".format(i)) for i in range(1, 6)])
group2 = asyncio.gather(*[coro("group 2.{}".format(i)) for i in range(1, 4)])
group3 = asyncio.gather(*[coro("group 3.{}".format(i)) for i in range(1, 10)])

all_groups = asyncio.gather(group1, group2, group3)

results = loop.run_until_complete(all_groups)

loop.close()

pprint(results)

งานทั้งหมดในกลุ่มสามารถยกเลิกได้โดยการเรียกหรือแม้กระทั่งgroup2.cancel() all_groups.cancel()ดูเพิ่มเติม.gather(..., return_exceptions=True),

asyncio.wait()

รองรับการรอที่จะหยุดหลังจากงานแรกเสร็จสิ้นหรือหลังจากหมดเวลาที่กำหนดช่วยให้การดำเนินงานมีความแม่นยำในระดับต่ำ:

import asyncio
import random


async def coro(tag):
    print(">", tag)
    await asyncio.sleep(random.uniform(0.5, 5))
    print("<", tag)
    return tag


loop = asyncio.get_event_loop()

tasks = [coro(i) for i in range(1, 11)]

print("Get first result:")
finished, unfinished = loop.run_until_complete(
    asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED))

for task in finished:
    print(task.result())
print("unfinished:", len(unfinished))

print("Get more results in 2 seconds:")
finished2, unfinished2 = loop.run_until_complete(
    asyncio.wait(unfinished, timeout=2))

for task in finished2:
    print(task.result())
print("unfinished2:", len(unfinished2))

print("Get all other results:")
finished3, unfinished3 = loop.run_until_complete(asyncio.wait(unfinished2))

for task in finished3:
    print(task.result())

loop.close()

5
"รูปแบบเครื่องหมายดอกจันเดียว (* args) ใช้เพื่อส่งรายการอาร์กิวเมนต์ที่ไม่มีคำสำคัญความยาวผันแปรและใช้รูปแบบเครื่องหมายดอกจันคู่เพื่อส่งผ่านรายการอาร์กิวเมนต์ที่มีความยาว
ผันคำหลัก

41

asyncio.waitasyncio.gatherเป็นระดับต่ำกว่า

ดังที่ชื่อแนะนำasyncio.gatherเน้นไปที่การรวบรวมผลลัพธ์เป็นหลัก มันกำลังรอฟิวเจอร์สจำนวนมากและส่งคืนผลลัพธ์ตามลำดับที่กำหนด

asyncio.waitแค่รออนาคต และแทนที่จะให้ผลลัพธ์โดยตรงกับคุณมันให้งานที่ทำและรอดำเนินการ คุณต้องรวบรวมค่าด้วยตนเอง

waitนอกจากนี้คุณสามารถระบุต้องรอให้ฟิวเจอร์สทั้งหมดจะเสร็จสิ้นหรือเพียงหนึ่งครั้งแรกกับ


it waits on a bunch of futures and return their results in a given orderคุณบอกว่า: จะเป็นอย่างไรถ้าฉันมีงาน 10000000000000 ชิ้นและทั้งหมดกลับมาเป็นข้อมูลขนาดใหญ่ ผลลัพธ์ทั้งหมดจะทำให้ความจำบูมเพิ่มขึ้นหรือไม่
Kingname

@Kingname ..wat
Matt Joiner

14

ฉันยังสังเกตเห็นว่าคุณสามารถให้กลุ่ม coroutines ใน wait () โดยเพียงแค่ระบุรายการ:

result=loop.run_until_complete(asyncio.wait([
        say('first hello', 2),
        say('second hello', 1),
        say('third hello', 4)
    ]))

ในขณะที่การรวมกลุ่มในรวบรวม () ทำได้โดยเพียงระบุหลาย coroutines:

result=loop.run_until_complete(asyncio.gather(
        say('first hello', 2),
        say('second hello', 1),
        say('third hello', 4)
    ))

20
รายการสามารถใช้กับgather()เช่น:asyncio.gather(*task_list)
tehfink

1
ดังนั้นเครื่องกำเนิดไฟฟ้าสามารถ
Jab

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