簡體   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