Asyncio และวงวนอนันต์

@asyncio.coroutine
    def listener():
        while True:
            message = yield from websocket.recieve_message()
            if message:
                yield from handle(message)

loop = asyncio.get_event_loop()
loop.run_until_complete(listener())

สมมติว่าฉันใช้ websockets กับ asyncio นั่นหมายความว่าฉันได้รับข้อความจาก websockets และเมื่อฉันได้รับข้อความ ฉันต้องการจัดการกับข้อความ แต่ฉันสูญเสียสิ่งที่ไม่ตรงกันทั้งหมดด้วยโค้ดของฉัน เนื่องจาก yield from handle(message) กำลังบล็อกอยู่อย่างแน่นอน... ฉันจะหาวิธีทำให้ไม่บล็อกได้อย่างไร เช่น จัดการหลายข้อความพร้อมกัน ไม่ต้องรอให้จัดการข้อความก่อนจึงจะสามารถจัดการข้อความอื่นได้

ขอบคุณ.


person Cookie    schedule 02.12.2015    source แหล่งที่มา
comment
โดยปกติแล้ว คุณจะต้องมีงานต่อ websocket ในการอ่าน การเขียนไปยัง websocket อาจดำเนินการแบบอะซิงโครนัสจากงานอื่น handle อาจเป็นงานแยกกันด้วย รหัสของคุณไม่สมบูรณ์ ดังนั้นจึงไม่ใช่เรื่องง่ายที่จะได้สิ่งที่คุณต้องการจริงๆ   -  person Andrew Svetlov    schedule 02.12.2015
comment
หากนี่เป็น coroutine เดียวที่คุณเรียกใช้ ผู้ฟังจะบล็อกในแง่ที่ว่ามันจะทำงานไม่สิ้นสุด (เนื่องจาก while วงจริง) หากคุณมี Coroutine อื่นที่ทำงานพร้อมกัน (โดยให้ผลตอบแทนจากคำสั่ง) asyncio จะตีกลับไปกลับมาระหว่างผลตอบแทนจากคำสั่งและจะหยุดเป็น 'บล็อก'   -  person songololo    schedule 02.12.2015


คำตอบ (1)


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

@asyncio.coroutine
def listener():
    while True:
        message = yield from websocket.recieve_message()
        if message:
            asyncio.ensure_future(handle(message))

ensure_future จะสร้างงานและแนบไปกับลูปเหตุการณ์เริ่มต้น เนื่องจากลูปกำลังทำงานอยู่แล้ว จึงจะได้รับการประมวลผลควบคู่ไปกับโปรแกรมอ่าน websocket ของคุณแบบขนาน ที่จริงแล้ว หากเป็นงาน I/O ที่ถูกบล็อกที่ทำงานช้า (เช่น การส่งอีเมล) คุณก็อาจมีงานจัดการ (ข้อความ) หลายสิบงานที่ทำงานพร้อมกันได้อย่างง่ายดาย พวกมันถูกสร้างขึ้นแบบไดนามิกเมื่อจำเป็น และถูกทำลายเมื่อเสร็จสิ้น (โดยมีค่าใช้จ่ายต่ำกว่าเธรดที่วางไข่มาก)

หากคุณต้องการการควบคุมเพิ่มเติมอีกเล็กน้อย คุณสามารถเขียนถึง asyncio.Queue ในเครื่องอ่านและมีกลุ่มงานที่มีขนาดคงที่ซึ่งสามารถใช้คิวได้ ซึ่งเป็นรูปแบบทั่วไปในการเขียนโปรแกรมแบบมัลติเธรดหรือหลายกระบวนการ

@asyncio.coroutine
def consumer(queue):
    while True:
        message = yield from queue.get()
        yield from handle(message)

@asyncio.coroutine
def listener(queue):
    for i in range(5):
         asyncio.ensure_future(consumer(queue))
    while True:
        message = yield from websocket.recieve_message()
        if message:
            yield from q.put(message)

q = asyncio.Queue()
loop = asyncio.get_event_loop()
loop.run_until_complete(listener(q))
person Ethan Frey    schedule 02.02.2016