Python中asyncio模塊使用詳解
概述
Python中 asyncio 模塊內(nèi)置了對異步IO的支持,用于處理異步IO;是Python 3.4版本引入的標(biāo)準(zhǔn)庫。
asyncio 的編程模型就是一個(gè)消息循環(huán)。
我們從 asyncio 塊中直接獲取一個(gè) EventLoop 的引用,然后把需要執(zhí)行的協(xié)程扔到 EventLoop 中執(zhí)行,就實(shí)現(xiàn)了異步IO。
用asyncio實(shí)現(xiàn)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!")
# 異步調(diào)用asyncio.sleep(2):
yield from asyncio.sleep(2)
print("Hello again!")
# 獲取EventLoop:
loop = asyncio.get_event_loop()
# 執(zhí)行coroutine
loop.run_until_complete(hello())
loop.close()@asyncio.coroutine 把一個(gè) generator 標(biāo)記為 coroutine 類型,然后,我們就把這個(gè) coroutine 扔到 EventLoop 中執(zhí)行。
hello() 會(huì)首先打印出Hello world!,然后,yield from語法可以讓我們方便地調(diào)用另一個(gè)generator。由于 asyncio.sleep() 也是一個(gè) coroutine,所以線程不會(huì)等待 asyncio.sleep() ,而是直接中斷并執(zhí)行下一個(gè)消息循環(huán)。
當(dāng)asyncio.sleep()返回時(shí),線程就可以從yield from拿到返回值(此處是None),然后接著執(zhí)行下一行語句。
把a(bǔ)syncio.sleep(2)看成是一個(gè)耗時(shí)2秒的IO操作(比如讀取大文件),在此期間,主線程并未等待,而是去執(zhí)行 EventLoop 中其他可以執(zhí)行的 coroutine 了,因此可以實(shí)現(xiàn)并發(fā)執(zhí)行。
我們用task封裝兩個(gè)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()觀察執(zhí)行過程:
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)>)
由打印的當(dāng)前線程名稱可以看出,兩個(gè) coroutine 是由同一個(gè)線程并發(fā)執(zhí)行的。
如果把 asyncio.sleep() 換成真正的IO操作,則多個(gè) coroutine 就可以由一個(gè)線程并發(fā)執(zhí)行。
我們用asyncio的異步網(wǎng)絡(luò)連接來獲取sina、sohu和163的網(wǎng)站首頁:
import asyncio
@asyncio.coroutine
def wget(host):
print('wget %s...' % host)
connect = asyncio.open_connection(host, 80) # 創(chuàng)建連接
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()執(zhí)行結(jié)果如下:
wget www.sohu.com...
wget www.sina.com.cn...
wget www.163.com...
(等待一段時(shí)間)
(打印出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個(gè)連接由一個(gè)線程通過coroutine并發(fā)完成。
總結(jié)
asyncio提供了完善的異步IO支持;
異步操作需要在coroutine中通過yield from完成;
多個(gè)coroutine可以封裝成一組Task然后并發(fā)執(zhí)行。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Python使用pyinstaller實(shí)現(xiàn)學(xué)生管理系統(tǒng)流程
pyinstaller是一個(gè)非常簡單的打包python的py文件的庫,下面這篇文章主要給大家介紹了關(guān)于Python?Pyinstaller庫安裝步驟以及使用方法的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02
淺談keras2 predict和fit_generator的坑
這篇文章主要介紹了淺談keras2 predict和fit_generator的坑,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-06-06
用Python程序抓取網(wǎng)頁的HTML信息的一個(gè)小實(shí)例
這篇文章主要介紹了用Python程序抓取網(wǎng)頁的HTML信息的一個(gè)小實(shí)例,用到的方法同時(shí)也是用Python編寫爬蟲的基礎(chǔ),需要的朋友可以參考下2015-05-05
Linux添加Python?path方法及修改環(huán)境變量的三種方法
這篇文章主要介紹了Linux添加Python?path方法及修改環(huán)境變量的三種方法,Linux 下設(shè)置環(huán)境變量有三種方法,一種用于當(dāng)前終端,一種用于當(dāng)前用戶,一種用于所有用戶,本文對每種方法給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07
python3模塊smtplib實(shí)現(xiàn)發(fā)送郵件功能
這篇文章主要為大家詳細(xì)介紹了python3模塊smtplib實(shí)現(xiàn)發(fā)送郵件功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05
Python 實(shí)現(xiàn)鍵盤鼠標(biāo)按鍵模擬
這篇文章主要介紹了Python 實(shí)現(xiàn)鍵盤按鍵模擬的方法,幫助大家提高辦公效率,感興趣的朋友可以了解下2020-11-11
Pytest生成測試報(bào)告的實(shí)現(xiàn)
本文介紹了如何使用 pytest-html 插件生成測試報(bào)告,并提供了詳細(xì)的操作步驟、配置項(xiàng)和示例代碼,具有一定的參考價(jià)值,感興趣的可以了解一下2023-11-11
解決Python paramiko 模塊遠(yuǎn)程執(zhí)行ssh 命令 nohup 不生效的問題
這篇文章主要介紹了解決Python paramiko 模塊遠(yuǎn)程執(zhí)行ssh 命令 nohup 不生效的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07

