阻塞型I/O和GIL
CPython 解釋器本身就不是線程安全的,因此有全局解釋器鎖(GIL),一次只允許使用一個線程執行 Python 字節碼。因此,一個 Python 進程通常不能同時使用多個 CPU 核心。
然而,標準庫中所有執行阻塞型 I/O 操作的函數,在等待操作系統返回結果時都會釋放GIL。這意味著在 Python 語言這個層次上可以使用多線程,而 I/O 密集型 Python 程序能從中受益:一個 Python 線程等待網絡響應時,阻塞型 I/O 函數會釋放 GIL,再運行一個線程。
asyncio
這個包使用事件循環驅動的協程實現并發。 asyncio 大量使用 yield from 表達式,因此與Python 舊版不兼容。
asyncio 包使用的“協程”是較嚴格的定義。適合asyncio API 的協程在定義體中必須使用 yield from,而不能使用 yield。此外,適合 asyncio 的協程要由調用方驅動,并由調用方通過 yield from 調用;
示例1
import threadingimport asyncio@asyncio.coroutinedef hello(): print('Start Hello', threading.currentThread()) yield from asyncio.sleep(5) print('End Hello', threading.currentThread())@asyncio.coroutinedef world(): print('Start World', threading.currentThread()) yield from asyncio.sleep(3) print('End World', threading.currentThread())# 獲取EventLoop:loop = asyncio.get_event_loop()tasks = [hello(), world()]# 執行coroutineloop.run_until_complete(asyncio.wait(tasks))loop.close()@asyncio.coroutine把生成器函數標記為協程類型。
asyncio.sleep(3) 創建一個3秒后完成的協程。
loop.run_until_complete(future),運行直到future完成;如果參數是 coroutine object,則需要使用 ensure_future()函數包裝。
loop.close() 關閉事件循環
示例2
import asyncio@asyncio.coroutinedef worker(text): """ 協程運行的函數 :param text: :return: """ i = 0 while True: print(text, i) try: yield from asyncio.sleep(.1) except asyncio.CancelledError: break i += 1@asyncio.coroutinedef client(text, io_used): worker_fu = asyncio.ensure_future(worker(text)) # 假裝等待I/O一段時間 yield from asyncio.sleep(io_used) # 結束運行協程 worker_fu.cancel() return 'done'loop = asyncio.get_event_loop()tasks = [client('xiaozhe', 3), client('zzzz', 5)]result = loop.run_until_complete(asyncio.wait(tasks))loop.close()print('Answer:', result)解釋:
1. asyncio.ensure_future(coro_or_future, *, loop=None):計劃安排一個 coroutine object的執行,返回一個 asyncio.Task object。
2. worker_fu.cancel(): 取消一個協程的執行,拋出CancelledError異常。
3. asyncio.wait():協程的參數是一個由期物或協程構成的可迭代對象; wait 會分別把各個協程包裝進一個 Task 對象。
asyncio.Task 對象與threading.Thread對象的比較
新聞熱點
疑難解答