Non-blocking I/O with asyncio

前端 未结 3 607
小鲜肉
小鲜肉 2021-02-01 05:22

I\'m trying to write a networked game with Pygame and asyncio, but I can\'t work out how to avoid hanging on reads. Here is my code for the client:

@asyncio.coro         


        
相关标签:
3条回答
  • 2021-02-01 05:39

    The point of yield from is to switch the execution to the asyncio's event loop and to block the current coroutine until the result is available. To schedule a task without blocking the current coroutine, you could use asyncio.async().

    To print read-so-far data without blocking the pygame loop:

    @asyncio.coroutine
    def read(reader, callback):
        while True:
            data = yield from reader.read(2**12)
            if not data: # EOF
                break
            callback(data)
    
    @asyncio.coroutine
    def echo_client():
        reader, ...
        chunks = []
        asyncio.async(read(reader, chunks.append))
        while True:
            pygame.event.pump() # advance pygame event loop
            ...
            if chunks: # print read-so-far data
                print(b''.join(chunks).decode())
                del chunks[:]
            yield from asyncio.sleep(0.016) # advance asyncio loop
    

    There should be no blocking calls inside the while loop.

    read() and sleep() coroutines run concurrently in the same thread (obviously you could run other coroutines concurrently too).

    0 讨论(0)
  • 2021-02-01 05:47

    well since you are trying to read the value of 'line' right after you call read() you need that value at any cost...

    if the coroutine wouldn't stop cause there are no data, you could get an AttributeError on the line.decode() call if 'line' then is None.

    one thing you can do is to set a timeout on the blocking call and handle the timeout exception:

    ...
    print("Waiting to read")
    try:  # block at most for one second
        line = yield from asyncio.wait_for(reader.read(2**12), 1)
    except asyncio.TimeoutError:
        continue
    else:
        print(line.decode())
    ...
    
    0 讨论(0)
  • 2021-02-01 05:51

    You can "transform" a blocking task into a non-blocking one.

    I suggest this: https://docs.python.org/3/library/asyncio-eventloop.html#executor.

    I have a function that listens to a twitter feed, function "mention", and I run it in an executor, so if it hangs, it doesn't block the other tasks.

    @asyncio.coroutine
    def boucle_deux():
    #faire attendre la boucle si pas bcp de mots
        while True:
            print("debut du deux")
            value = t.next()
            future2 = loop.run_in_executor(None, mention, "LQNyL2xvt9OQMvje7jryaHkN8",
                                           "IRJX6S17K44t8oiVGCjrj6XCVKqGSX9ClfpGpfC467rajqePGb",
                                           "2693346740-km3Ufby8r9BbYpyzcqwiHhss22h4YkmnPN4LnLM",
                                           "53R8GAAncFJ1aHA1yJe1OICfjqUbqwcMR38wSqvbzsQMB", 23, value)
            response2 = yield from future2
            yield from asyncio.sleep(5)
            print("fin du deux")
    
    asyncio.Task(boucle_deux())
    
    0 讨论(0)
提交回复
热议问题