[英]Can an asyncio event loop run in the background without suspending the Python interpreter?
[英]python asyncio run event loop once?
我試圖了解asyncio庫,特別是使用套接字。 我寫了一些代碼以試圖獲得理解,
我想異步運行發送器和接收器套接字。 我到了最后一個發送所有數據的地步,但是我必須再運行一個循環。 看看如何做到這一點,我從stackoverflow找到了這個鏈接 ,我在下面實現了 - 但是這里發生了什么? 有沒有更好/更理智的方法來做到這一點,而不是調用stop
后跟run_forever
?
事件循環中stop()
的文檔是:
停止運行事件循環。
調用stop()之前安排的每個回調都將運行。 調用stop()后調度的回調將不會運行。 但是,如果稍后再次調用run_forever(),則會運行這些回調。
而run_forever()
的文檔是:
運行直到調用stop()。
問題:
run_forever
的唯一途徑run_once
? 這甚至沒有意義 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.