Python中asyncio模塊的深入講解
1. 概述
Python中 asyncio 模塊內(nèi)置了對(duì)異步IO的支持,用于處理異步IO;是Python 3.4版本引入的標(biāo)準(zhǔn)庫(kù)。
asyncio 的編程模型就是一個(gè)消息循環(huán)。我們從 asyncio 塊中直接獲取一個(gè) EventLoop 的引用,然后把需要執(zhí)行的協(xié)程扔到 EventLoop 中執(zhí)行,就實(shí)現(xiàn)了異步IO。
2. 用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 類(lèi)型,然后,我們就把這個(gè) coroutine 扔到 EventLoop 中執(zhí)行。
hello() 會(huì)首先打印出Hello world!,然后,yield from語(yǔ)法可以讓我們方便地調(diào)用另一個(gè)generator。由于 asyncio.sleep() 也是一個(gè) coroutine,所以線(xiàn)程不會(huì)等待 asyncio.sleep() ,而是直接中斷并執(zhí)行下一個(gè)消息循環(huán)。當(dāng)asyncio.sleep()返回時(shí),線(xiàn)程就可以從yield from拿到返回值(此處是None),然后接著執(zhí)行下一行語(yǔ)句。
把a(bǔ)syncio.sleep(2)看成是一個(gè)耗時(shí)2秒的IO操作(比如讀取大文件),在此期間,主線(xiàn)程并未等待,而是去執(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()
觀(guān)察執(zhí)行過(guò)程:
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)前線(xiàn)程名稱(chēng)可以看出,兩個(gè) coroutine 是由同一個(gè)線(xiàn)程并發(fā)執(zhí)行的。
如果把 asyncio.sleep() 換成真正的IO操作,則多個(gè) coroutine 就可以由一個(gè)線(xiàn)程并發(fā)執(zhí)行。
我們用asyncio的異步網(wǎng)絡(luò)連接來(lái)獲取sina、sohu和163的網(wǎng)站首頁(yè):
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
...
可見(jiàn)3個(gè)連接由一個(gè)線(xiàn)程通過(guò)coroutine并發(fā)完成。
3. 小結(jié)
asyncio提供了完善的異步IO支持;
異步操作需要在coroutine中通過(guò)yield from完成;
多個(gè)coroutine可以封裝成一組Task然后并發(fā)執(zhí)行。
好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
- 在Python3中使用asyncio庫(kù)進(jìn)行快速數(shù)據(jù)抓取的教程
- 探索Python3.4中新引入的asyncio模塊
- Python中使用asyncio 封裝文件讀寫(xiě)
- Python使用asyncio包處理并發(fā)詳解
- Python中的并發(fā)處理之a(chǎn)syncio包使用的詳解
- 詳解python異步編程之a(chǎn)syncio(百萬(wàn)并發(fā))
- Python中asyncio與aiohttp入門(mén)教程
- Python中的asyncio代碼詳解
- python協(xié)程與?asyncio?庫(kù)詳情
- Python中asyncio的多種用法舉例(異步同步)
相關(guān)文章
python一行sql太長(zhǎng)折成多行并且有多個(gè)參數(shù)的方法
今天小編就為大家分享一篇python一行sql太長(zhǎng)折成多行并且有多個(gè)參數(shù)的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-07-07
Python面向?qū)ο蟪绦蛟O(shè)計(jì)類(lèi)的多態(tài)用法詳解
這篇文章主要介紹了Python面向?qū)ο蟪绦蛟O(shè)計(jì)類(lèi)的多態(tài)用法,結(jié)合實(shí)例形式詳細(xì)分析了Python面向?qū)ο蟪绦蛟O(shè)計(jì)中類(lèi)的多態(tài)概念、原理、用法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2019-04-04
Python庫(kù)學(xué)習(xí)Tkinter制作GUI個(gè)性簽名設(shè)計(jì)軟件
Tkinter 是 Python 中的標(biāo)準(zhǔn) GUI 庫(kù),使用 Tkinter 可以快速地創(chuàng)建 GUI 應(yīng)用程序。今天我們打算再用一個(gè)小案例,帶大家加深對(duì)Tkinter的理解2021-09-09
python3翻轉(zhuǎn)字符串里的單詞點(diǎn)的實(shí)現(xiàn)方法
這篇文章主要介紹了python3翻轉(zhuǎn)字符串里的單詞點(diǎn)的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
python中的torch常用tensor處理函數(shù)示例詳解
這篇文章主要介紹了python中的torch常用tensor處理函數(shù),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07
python網(wǎng)絡(luò)編程學(xué)習(xí)筆記(五):socket的一些補(bǔ)充
前面已經(jīng)為大家介紹了python socket的一些相關(guān)知識(shí),這里為大家補(bǔ)充下,方便需要的朋友2014-06-06
Python圖像處理之圖像的讀取、顯示與保存操作【測(cè)試可用】
這篇文章主要介紹了Python圖像處理之圖像的讀取、顯示與保存操作,結(jié)合實(shí)例形式分析了Python使用PIL模塊、scipy和matplotlib模塊進(jìn)行圖像讀寫(xiě)、顯示等相關(guān)操作技巧,需要的朋友可以參考下2019-01-01
Python如何統(tǒng)計(jì)大小寫(xiě)字母?jìng)€(gè)數(shù)和數(shù)字個(gè)數(shù)
這篇文章主要介紹了Python如何統(tǒng)計(jì)大小寫(xiě)字母?jìng)€(gè)數(shù)和數(shù)字個(gè)數(shù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08
python實(shí)現(xiàn)計(jì)算資源圖標(biāo)crc值的方法
這篇文章主要介紹了python實(shí)現(xiàn)計(jì)算資源圖標(biāo)crc值的方法,通過(guò)解析資源文件找到icon的數(shù)據(jù),從而實(shí)現(xiàn)該功能,需要的朋友可以參考下2014-10-10
python實(shí)現(xiàn)的正則表達(dá)式功能入門(mén)教程【經(jīng)典】
這篇文章主要介紹了python實(shí)現(xiàn)的正則表達(dá)式功能,詳細(xì)分析了Python正則表達(dá)式中常用的各種符號(hào)、函數(shù)等的使用方法與注意事項(xiàng),需要的朋友可以參考下2017-06-06

