簡單瞭解一下事件循環(Event Loop)

關於我
一個有思想的程序猿,終身學習實踐者,目前在一個創業團隊任team lead,技術棧涉及Android、Python、Java和Go,這個也是咱們團隊的主要技術棧。
Github:https://github.com/hylinux1024
微信公衆號:終身開發者(angrycode)html

0x00 事件循環(Event Loop)

在前文《爲什麼你還不懂得如何使用Python協程
中提到協程是經過asyncio包中的高級API來啓動的。而asyncio模塊中的核心就是事件循環(Event Loop)。它可用於執行異步任務、事件回調、執行網絡IO操做和運行子進程。官方的文檔也是建議開發者應該儘可能使用asyncio包提供的高級的API,避免直接使用Event Loop對象中的方法。python

系統提供的底層能力的功能模塊例如網絡鏈接、文件IO等都會使用到looplinux

大多數狀況下,這些高級API能夠知足衆多使用場景,但做爲一個有追求的猿類,應該要有一點點探索的精神,看看在asyncio封裝之下的Event Loopgit

獲取Event Loop對象
  • asyncio.get_running_loop()
    獲取當前系統線程正在使用的loop對象
  • asyncio.get_event_loop()
    獲取當前正在使用的loop對象。若是當前系統線程尚未loop對象,那麼就會建立一個新的loop對象,並使用asyncio.set_event_loop(loop)方法設置到當前系統線程中。
  • asyncio.new_event_loop()
    建立一個新的loop對象
  • asyncio.set_event_loop(loop)
    loop設置成系統線程使用的對象

Event Loop對象的經常使用方法

若是使用相似asyncio.run()這些高級API,如下這些方法,基本上不多會用到,建議通讀一下,大概知道loop對象擁有哪些API,瞭解如下底層的實現細節。github

啓動和中止
  • loop.run_until_complete(future)
    future對象執行完成才返回
  • loop.run_forever()
    一直運行,直到調用了loop.stop()方法
  • loop.stop()
    中止loop對象
  • loop.is_running()
    判斷loop是否正在運行
  • loop.is_closed()
    判斷loop是否關閉
  • loop.close()
    關閉loop對象
  • coroutine loop.shutdown_asyncgens()
try:
    loop.run_forever()
finally:
    loop.run_until_complete(loop.shutdown_asyncgens())
    loop.close()
回調方法
  • loop.call_soon(callback, *args, context=None)
    在事件循環的下一次迭代中執行callback方法,args是方法中的參數
  • loop.call_soon_threadsafe(callback, *args, context=None)
    線程安全的call_soon()
iimport asyncio
import time

def hello_world(loop):
    print('Hello World')
    time.sleep(3)  # 模擬長時間操做
    loop.stop()

loop = asyncio.get_event_loop()

# 使用loop執行 hello_world()
loop.call_soon(hello_world, loop)

# 會一直阻塞,直到調用了stop方法
try:
    loop.run_forever()
finally:
    loop.close()
可延遲的回調方法

可設置延遲執行的方法windows

  • loop.call_later(delay, callback, *args, context=None)
    延遲delay秒後執行
  • loop.call_at(when, callback, *args, context=None)
    在指定時間點執行
  • loop.time()
    返回當前時間
import asyncio
import datetime


def display_date(end_time, loop):
    print(datetime.datetime.now())
    if (loop.time() + 1.0) < end_time:
        # 1秒後執行
        loop.call_later(1, display_date, end_time, loop)
    else:
        loop.stop()

loop = asyncio.get_event_loop()

# 執行5秒
end_time = loop.time() + 5.0
loop.call_soon(display_date, end_time, loop)

# 一直運行,等待stop的調用
try:
    loop.run_forever()
finally:
    loop.close()

執行結果打印5秒時間點安全

2019-05-09 22:34:47.885412
2019-05-09 22:34:48.887513
2019-05-09 22:34:49.889396
2019-05-09 22:34:50.894316
2019-05-09 22:34:51.898457
建立Future和Tasks
  • loop.create_future()
    建立一個綁定事件循環的future對象
  • loop.create_task(coro)
    coro放入調度,並返回task對象
  • loop.set_task_factory(factory)
    設置任務工廠
  • loop.get_task_factory()
    返回任務工廠,有可能返回None
建立網絡連
coroutine loop.create_connection(protocol_factory, host=None, port=None, *, ssl=None, family=0, proto=0, flags=0, sock=None, local_addr=None, server_hostname=None, ssl_handshake_timeout=None)

指定hostport等參數建立網絡鏈接微信

coroutine loop.create_datagram_endpoint(protocol_factory, local_addr=None, remote_addr=None, *, family=0, proto=0, flags=0, reuse_address=None, reuse_port=None, allow_broadcast=None, sock=None)

建立UDP鏈接網絡

coroutine loop.create_unix_connection(protocol_factory, path=None, *, ssl=None, sock=None, server_hostname=None, ssl_handshake_timeout=None)

建立Unix鏈接異步

coroutine loop.create_server(protocol_factory, host=None, port=None, *, family=socket.AF_UNSPEC, flags=socket.AI_PASSIVE, sock=None, backlog=100, ssl=None, reuse_address=None, reuse_port=None, ssl_handshake_timeout=None, start_serving=True)

建立TCP服務

coroutine loop.create_unix_server(protocol_factory, path=None, *, sock=None, backlog=100, ssl=None, ssl_handshake_timeout=None, start_serving=True)

建立Unix服務

coroutine loop.connect_accepted_socket(protocol_factory, sock, *, ssl=None, ssl_handshake_timeout=None)

封裝已創建的鏈接,返回元組(transport, protocol)

Event Loop 的實現

asyncio 的事件循環有兩種不一樣的實現:SelectorEventLoopProactorEventLoop,它們的父類是AbstractEventLoop

SelectorEventLoop

這個是asyncio默認使用的Event Loop實現,支持unixwindows平臺

import asyncio
import selectors

selector = selectors.SelectSelector()
loop = asyncio.SelectorEventLoop(selector)
asyncio.set_event_loop(loop)
ProactorEventLoop

這個是Windows平臺專有的實現

import asyncio
import sys

if sys.platform == 'win32':
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)

0x01 總結

事件循環是asyncio的核心,asncio模塊的不少高級接口是經過封裝Event Loop對象來實現的。它提供了執行異步任務、事件回調、執行網絡IO操做和運行子進程的能力。
本文是經過官方文檔對事件循環的概念和它的常見API作了一個大概的瞭解。做爲《前文》的補充

0x02 引用

  1. https://docs.python.org/3/library/asyncio-eventloop.html
相關文章
相關標籤/搜索