1. 概述
Python中 asyncio 模塊內置了對異步IO的支持,用于處理異步IO;是Python 3.4版本引入的標準庫。
asyncio 的編程模型就是一個消息循環。我們從 asyncio 塊中直接獲取一個 EventLoop 的引用,然后把需要執行的協程扔到 EventLoop 中執行,就實現了異步IO。
2. 用asyncio實現Hello world
#!/usr/bin/env python3 # -*- coding: utf-8 -*- # @Time : 2019/1/9 11:23 # @Author : Arrow and Bullet # @FileName: test.py # @Software: PyCharm # @Blog :https://blog.csdn.net/qq_41800366 import asyncio @asyncio.coroutine def hello(): print("Hello world!") # 異步調用asyncio.sleep(2): yield from asyncio.sleep(2) print("Hello again!") # 獲取EventLoop: loop = asyncio.get_event_loop() # 執行coroutine loop.run_until_complete(hello()) loop.close()
@asyncio.coroutine 把一個 generator 標記為 coroutine 類型,然后,我們就把這個 coroutine 扔到 EventLoop 中執行。
hello() 會首先打印出Hello world!,然后,yield from語法可以讓我們方便地調用另一個generator。由于 asyncio.sleep() 也是一個 coroutine,所以線程不會等待 asyncio.sleep() ,而是直接中斷并執行下一個消息循環。當asyncio.sleep()返回時,線程就可以從yield from拿到返回值(此處是None),然后接著執行下一行語句。
把asyncio.sleep(2)看成是一個耗時2秒的IO操作(比如讀取大文件),在此期間,主線程并未等待,而是去執行 EventLoop 中其他可以執行的 coroutine 了,因此可以實現并發執行。
我們用task封裝兩個coroutine試試:
import threading import asyncio @asyncio.coroutine def hello(): print('Hello world! (%s)' % threading.currentThread()) yield from asyncio.sleep(2) print('Hello again! (%s)' % threading.currentThread()) loop = asyncio.get_event_loop() tasks = [hello(), hello()] loop.run_until_complete(asyncio.wait(tasks)) loop.close()
觀察執行過程:
Hello world! (<_MainThread(MainThread, started 140735195337472)>)
Hello world! (<_MainThread(MainThread, started 140735195337472)>)
(暫停約2秒)
Hello again! (<_MainThread(MainThread, started 140735195337472)>)
Hello again! (<_MainThread(MainThread, started 140735195337472)>)
由打印的當前線程名稱可以看出,兩個 coroutine 是由同一個線程并發執行的。
如果把 asyncio.sleep() 換成真正的IO操作,則多個 coroutine 就可以由一個線程并發執行。
我們用asyncio的異步網絡連接來獲取sina、sohu和163的網站首頁:
import asyncio @asyncio.coroutine def wget(host): print('wget %s...' % host) connect = asyncio.open_connection(host, 80) # 創建連接 reader, writer = yield from connect header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' % host writer.write(header.encode('utf-8')) yield from writer.drain() while True: line = yield from reader.readline() if line == b'\r\n': break print('%s header > %s' % (host, line.decode('utf-8').rstrip())) # Ignore the body, close the socket writer.close() loop = asyncio.get_event_loop() tasks = [wget(host) for host in ['www.sina.com.cn', 'www.sohu.com', 'www.163.com']] loop.run_until_complete(asyncio.wait(tasks)) loop.close()
執行結果如下:
wget www.sohu.com...
wget www.sina.com.cn...
wget www.163.com...
(等待一段時間)
(打印出sohu的header)
www.sohu.com header > HTTP/1.1 200 OK
www.sohu.com header > Content-Type: text/html
...
(打印出sina的header)
www.sina.com.cn header > HTTP/1.1 200 OK
www.sina.com.cn header > Date: Wed, 20 May 2015 04:56:33 GMT
...
(打印出163的header)
www.163.com header > HTTP/1.0 302 Moved Temporarily
www.163.com header > Server: Cdn Cache Server V2.0
...
可見3個連接由一個線程通過coroutine并發完成。
3. 小結
asyncio提供了完善的異步IO支持;
異步操作需要在coroutine中通過yield from完成;
多個coroutine可以封裝成一組Task然后并發執行。
好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對腳本之家的支持。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
