繁体   English   中英

python asyncio运行事件循环一次?

[英]python asyncio run event loop once?

我试图了解asyncio库,特别是使用套接字。 我写了一些代码以试图获得理解,

我想异步运行发送器和接收器套接字。 我到了最后一个发送所有数据的地步,但是我必须再运行一个循环。 看看如何做到这一点,我从stackoverflow找到了这个链接 ,我在下面实现了 - 但是这里发生了什么? 有没有更好/更理智的方法来做到这一点,而不是调用stop后跟run_forever

事件循环中stop()的文档是:

停止运行事件循环。

调用stop()之前安排的每个回调都将运行。 调用stop()后调度的回调将不会运行。 但是,如果稍后再次调用run_forever(),则会运行这些回调。

run_forever()的文档是:

运行直到调用stop()。

问题:

  • 为什么在世界上是run_forever的唯一途径run_once 这甚至没有意义
  • 有一个更好的方法吗?
  • 我的代码看起来像是使用asyncio库编程的合理方式吗?
  • 除了asyncio.async()之外,还有更好的方法将事件添加到事件循环中吗? loop.create_task在我的Linux系统上出错。

https://gist.github.com/cloudformdesign/b30e0860497f19bd6596

stop(); run_forever() stop(); run_forever()技巧因为如何实现stop而起作用:

def stop(self):
    """Stop running the event loop.

    Every callback scheduled before stop() is called will run.
    Callback scheduled after stop() is called won't.  However,
    those callbacks will run if run() is called again later.
    """
    self.call_soon(_raise_stop_error)

def _raise_stop_error(*args):
    raise _StopError

因此,下次事件循环运行并执行挂起的回调时,它将调用_raise_stop_error ,这会引发_StopError run_forever循环仅在该特定异常上中断:

def run_forever(self):
    """Run until stop() is called."""
    if self._running:
        raise RuntimeError('Event loop is running.')
    self._running = True
    try:
        while True:
            try:
                self._run_once()
            except _StopError:
                break
    finally:
        self._running = False

因此,通过调度stop()然后调用run_forever ,您最终会运行事件循环的一次迭代,然后在遇到_raise_stop_error回调时停止。 您可能还注意到_run_once是由run_forever定义和调用的。 您可以直接调用它,但如果没有任何回调准备好运行,有时可以阻止,这可能是不可取的。 我认为目前没有更清洁的方法 - 答案是由安德asyncio提供的,他是一名asyncio撰稿人; 他可能会知道是否有更好的选择。 :)

通常,您的代码看起来很合理,但我认为您不应该使用此run_once方法开始。 这不是确定性的; 如果您有更长的列表或更慢的系统,可能需要两次以上的额外迭代来打印所有内容。 相反,你应该只发送一个告诉接收器关闭的标记,然后等待发送和接收协同程序完成:

import sys
import time
import socket
import asyncio


addr = ('127.0.0.1', 1064)
SENTINEL = b"_DONE_" 

# ... (This stuff is the same)

@asyncio.coroutine
def sending(addr, dataiter):
    loop = asyncio.get_event_loop()
    for d in dataiter:
        print("Sending:", d)
        sock = socket.socket()
        yield from send_close(loop, sock, addr, str(d).encode())
    # Send a sentinel
    sock = socket.socket()
    yield from send_close(loop, sock, addr, SENTINEL)

@asyncio.coroutine
def receiving(addr):
    loop = asyncio.get_event_loop()
    sock = socket.socket()
    try:
        sock.setblocking(False)
        sock.bind(addr)
        sock.listen(5)

        while True:
            data = yield from accept_recv(loop, sock)
            if data == SENTINEL:  # Got a sentinel
                return
            print("Recevied:", data)
    finally: sock.close()

def main():
    loop = asyncio.get_event_loop()
    # add these items to the event loop
    recv = asyncio.async(receiving(addr), loop=loop)
    send = asyncio.async(sending(addr, range(10)), loop=loop)
    loop.run_until_complete(asyncio.wait([recv, send]))

main()

最后, asyncio.async是向事件循环添加任务的正确方法。 create_task是在Python 3.4.2中添加的,所以如果你有一个早期版本它将不存在。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM