標(biāo)準(zhǔn)Python程序很容易過載,從而出現(xiàn)慢如龜爬的情況。asyncio庫正是為了解決這些問題而構(gòu)建的,它簡化了任務(wù)的劃分和調(diào)度。asyncio可無縫地同時(shí)處理多個(gè)操作,使應(yīng)用程序疾如閃電,且具有擴(kuò)展性。 《Python asyncio并發(fā)編程》在大量示例的引導(dǎo)下,介紹異步、并行和并發(fā)編程。將難理解的并發(fā)內(nèi)容分解為簡明易懂的流程圖,使讀者可輕松了解任務(wù)的運(yùn)行方式。在本書中,讀者將學(xué)習(xí)如何使用asyncio來突破Python的限制,從而加快Web服務(wù)器和微服務(wù)的運(yùn)行速度。讀者甚至可將asyncio與傳統(tǒng)的多處理技術(shù)結(jié)合起來,以大幅提升性能。 主要內(nèi)容 ● 通過aiohttp構(gòu)建支持并發(fā)Web請求的Web API ● 同時(shí)運(yùn)行海量SQL查詢 ● 創(chuàng)建一個(gè)可并行處理數(shù)GB數(shù)據(jù)的map-reduce作業(yè) ● 在asyncio中使用線程來混合阻塞代碼和asyncio代碼
在本書中,通過14章的內(nèi)容,由淺入深地介紹如何通過asyncio實(shí)現(xiàn)并發(fā)編程,并使用 一個(gè)貫穿全書的示例,介紹如何使用asyncio 在服務(wù)器與客戶端之間進(jìn)行并發(fā)通信?粗@個(gè)示例由簡單變得復(fù)雜,在掌握相關(guān)知識(shí)的同時(shí),也給自己帶來了不小的成就感。作為Python和數(shù)據(jù)科學(xué)的教學(xué)人員,我建議你在閱讀本書時(shí),認(rèn)真學(xué)習(xí)書中的示例,并在自己的計(jì)算機(jī)上運(yùn)行本書附帶的程序,這將讓你更好地理解本書所介紹的內(nèi)容。別擔(dān)心,本書使用的示例對計(jì)算機(jī)的要求并不高;我在完成相關(guān)練習(xí)時(shí),使用的是2015年在拉斯維加斯的Best buy購買的MacBook Pro,配置i5 CPU、8GB
內(nèi)存及128GB SSD,使用這樣的機(jī)器運(yùn)行本書的示例代碼毫無壓力。
《Python asyncio并發(fā)編程》旨在介紹如何在Python中利用并行技術(shù)提高應(yīng)用程序的性能、吞吐量和響應(yīng)能力。本書首先關(guān)注并行的核心主題,解釋asyncio的單線程并發(fā)模型是如何工作的,以及協(xié)程和async/await語法的工作原理。然后介紹并發(fā)的實(shí)際應(yīng)用,例如并行發(fā)出多個(gè) Web 請求或數(shù)據(jù)庫查詢、管理線程和進(jìn)程、構(gòu)建Web應(yīng)用程序,以及處理同步問題。
目標(biāo)讀者
本書適用于希望在現(xiàn)有或新的Python應(yīng)用程序中,更好地理解和使用并發(fā)技術(shù)的中高級(jí)開發(fā)人員。本書的立足于在于通過通俗易懂的語言解釋復(fù)雜的并發(fā)技術(shù)。你不需要擁有并發(fā)經(jīng)驗(yàn),當(dāng)然,如果你擁有這方面的經(jīng)驗(yàn),可以更快地理解書中的內(nèi)容。在本書中,我們將介紹很多知識(shí)(從基于Web的API到命令行應(yīng)用程序),幫助開發(fā)人員解決工作中遇到的許多問題。
內(nèi)容路線圖
本書一共14章,前幾章介紹基礎(chǔ)知識(shí),后幾章將介紹更多高級(jí)主題。
● 第1章:專注于Python中的基本并發(fā)知識(shí)。將介紹什么是CPU密集型和I/O密集型工作負(fù)載,并介紹asyncio的單線程并發(fā)模型的工作原理。
● 第2章:重點(diǎn)介紹asyncio協(xié)程的基礎(chǔ)知識(shí),以及如何使用async/await語法來構(gòu)建使用并發(fā)的應(yīng)用程序。
● 第3章:重點(diǎn)介紹非阻塞套接字和選擇器如何工作,以及如何使用asyncio構(gòu)建echo服務(wù)器。
● 第4章:重點(diǎn)介紹如何同時(shí)發(fā)出多個(gè)Web請求。通過本章的學(xué)習(xí),我們將進(jìn)一步了解關(guān)于并發(fā)運(yùn)行協(xié)同程序的核心asyncio API。
● 第5章:重點(diǎn)介紹如何使用連接池同時(shí)進(jìn)行多個(gè)數(shù)據(jù)庫查詢。還將介紹數(shù)據(jù)庫上下文中的異步上下文管理器和異步生成器。
● 第6章:專注于multiprocessing庫,特別是如何將它與asyncio結(jié)合,來處理CPU密集型工作。將構(gòu)建一個(gè)map/reduce應(yīng)用程序來介紹它的工作方法。
● 第7章:專注于多線程,特別是如何將它與asyncio結(jié)合來處理阻塞I/O。這對于沒有原生asyncio支持但仍然可以從并發(fā)中受益的庫很有幫助。
● 第8章:著重介紹網(wǎng)絡(luò)流和協(xié)議。將使用網(wǎng)絡(luò)流和協(xié)議來創(chuàng)建一個(gè)能同時(shí)處理多個(gè)用戶聊天的服務(wù)器和客戶端。
● 第9章:主要介紹異步驅(qū)動(dòng)的Web應(yīng)用程序和ASGI(異步服務(wù)器網(wǎng)關(guān)接口)。將探索一些ASGI框架,并討論如何使用它們構(gòu)建Web API。還將探索 WebSocket。
● 第10章:描述如何使用基于asyncio的Web API來構(gòu)建微服務(wù)架構(gòu)。
● 第11章:重點(diǎn)討論單線程并發(fā)同步問題,以及如何解決這些問題。將深入研究鎖、信號(hào)量、事件和條件。
● 第12章:重點(diǎn)關(guān)注異步隊(duì)列。將使用異步隊(duì)列來構(gòu)建一個(gè)Web應(yīng)用程序,該應(yīng)用程序可以即時(shí)響應(yīng)客戶端請求,盡管需要在后臺(tái)執(zhí)行耗時(shí)的工作。
● 第13章:專注于創(chuàng)建和管理子進(jìn)程,展示如何讀取和寫入數(shù)據(jù)。
● 第14章:專注于高級(jí)主題,例如強(qiáng)制事件循環(huán)迭代、上下文變量和創(chuàng)建自己的事件循環(huán)。這些信息對于asyncio API設(shè)計(jì)者和那些對asyncio事件循環(huán)的內(nèi)部運(yùn)作流程感興趣的人十分有幫助。
對于讀者來說,你應(yīng)該仔細(xì)閱讀前四章的內(nèi)容,從而全面了解asyncio的工作原理、如何構(gòu)建第一個(gè)真正的應(yīng)用程序,以及如何使用核心asyncio API來并行運(yùn)行協(xié)同程序(將在第4章中介紹)。此后,你可以根據(jù)自己的興趣來閱讀本書。
關(guān)于代碼
本書包含許多代碼示例,包括編號(hào)的代碼清單。一些代碼清單在同一章后面的清單中被重用,有些則在多個(gè)章節(jié)中被重用。對于跨多個(gè)章節(jié)重用的代碼,將假定你已經(jīng)創(chuàng)建了一個(gè)名為util的模塊(你將在第2章中創(chuàng)建它)。對于每個(gè)單獨(dú)的代碼清單,假設(shè)你為該章創(chuàng)建了一個(gè)名為chapter_{chapter_number}的模塊,然后將代碼放入格式為listing_{chapter_number}_{listing_number}的Python文件中。例如,第2章中清單2-2的代碼將位于一個(gè)名為chapter_2的模塊中,該模塊保存在名為listing_2_2.py的文件中。
書中多處提到性能數(shù)字,例如程序完成的時(shí)間或每秒完成的Web請求。本書中的代碼示例運(yùn)行在配備2.4GHz 8 核 Intel Core i9處理器和 32GB 2667 MHz DDR4 RAM 的2019 MacBook Pro上,并進(jìn)行了基準(zhǔn)測試,使用千兆無線互聯(lián)網(wǎng)連接。根據(jù)你運(yùn)行的機(jī)器,這些數(shù)字會(huì)有所不同,加速或改進(jìn)的因素也會(huì)有所不同。
本書中使用的代碼可通過掃描封底二維碼下載。
Matthew Fowler擁有近20年的軟件工程經(jīng)驗(yàn),曾任軟件架構(gòu)師、工程總監(jiān)等多個(gè)職位。他起初為科學(xué)應(yīng)用程序編寫軟件,然后轉(zhuǎn)向全棧Web開發(fā)和分布式系統(tǒng),最終領(lǐng)導(dǎo)多個(gè)開發(fā)人員和管理人員團(tuán)隊(duì)為擁有數(shù)千萬用戶的電子商務(wù)網(wǎng)站編寫應(yīng)用程序及構(gòu)建系統(tǒng)。他與妻子Kathy住在馬薩諸塞州的列克星敦。
第1 章 asyncio簡介 1
1.1 什么是asyncio 2
1.2 什么是I/O密集型和CPU密集型 3
1.3 了解并發(fā)、并行和多任務(wù)處理 4
1.3.1 并發(fā) 4
1.3.2 并行 5
1.3.3 并行與并發(fā)的區(qū)別 6
1.3.4 什么是多任務(wù) 6
1.3.5 協(xié)同多任務(wù)處理的優(yōu)勢 7
1.4 了解進(jìn)程、線程、多線程和多處理 7
1.4.1 進(jìn)程 7
1.4.2 線程 8
1.5 理解全局解釋器鎖 11
1.5.1 GIL會(huì)釋放嗎 15
1.5.2 asyncio和GIL 17
1.6 單線程并發(fā) 17
1.7 事件循環(huán)的工作原理 20
1.8 本章小結(jié) 22
第2 章 asyncio基礎(chǔ) 23
2.1 關(guān)于協(xié)程 23
2.1.1 使用async關(guān)鍵字創(chuàng)建協(xié)程 24
2.1.2 使用await關(guān)鍵字暫停執(zhí)行 26
2.2 使用sleep引入長時(shí)間運(yùn)行的協(xié)程 27
2.3 通過任務(wù)實(shí)現(xiàn)并行 30
2.3.1 創(chuàng)建任務(wù) 30
2.3.2 同時(shí)運(yùn)行多個(gè)任務(wù) 31
2.4 取消任務(wù)和設(shè)置超時(shí) 34
2.4.1 取消任務(wù) 34
2.4.2 設(shè)置超時(shí)并使用wait_for
執(zhí)行取消 36
2.5 任務(wù)、協(xié)程、future和awaitable 38
2.5.1 關(guān)于future 38
2.5.2 future、任務(wù)和協(xié)程之間的關(guān)系 40
2.6 使用裝飾器測量協(xié)程執(zhí)行時(shí)間 41
2.7 協(xié)程和任務(wù)的陷阱 43
2.7.1 運(yùn)行CPU密集型代碼 44
2.7.2 運(yùn)行阻塞API 46
2.8 手動(dòng)創(chuàng)建和訪問事件循環(huán) 47
2.8.1 手動(dòng)創(chuàng)建事件循環(huán) 47
2.8.2 訪問事件循環(huán) 48
2.9 使用調(diào)試模式 49
2.9.1 使用asyncio.run 49
2.9.2 使用命令行參數(shù) 49
2.9.3 使用環(huán)境變量 50
2.10 本章小結(jié) 51
第3 章 第一個(gè)asyncio應(yīng)用程序 53
3.1 使用阻塞套接字 54
3.2 使用telnet連接到服務(wù)器 56
3.2.1 從套接字讀取和寫入數(shù)據(jù) 57
3.2.2 允許多個(gè)連接和阻塞的危險(xiǎn)性 59
3.3 使用非阻塞套接字 61
3.4 使用選擇器模塊構(gòu)建套接字事件循環(huán) 65
3.5 使用asyncio事件循環(huán)的
回顯服務(wù)器 68
3.5.1 套接字的事件循環(huán)協(xié)程 69
3.5.2 設(shè)計(jì)一個(gè)異步回顯服務(wù)器 69
3.5.3 解決任務(wù)中的錯(cuò)誤 72
3.6 正常關(guān)閉 74
3.6.1 監(jiān)聽信號(hào) 74
3.6.2 等待掛起的任務(wù)完成 76
3.7 本章小結(jié) 79
第4 章 并發(fā)網(wǎng)絡(luò)請求 81
4.1 aiohttp 82
4.2 異步上下文管理器 82
4.2.1 使用aiohttp發(fā)出Web請求 85
4.2.2 使用aiohttp設(shè)置超時(shí) 87
4.3 并發(fā)運(yùn)行任務(wù)及重新訪問 88
4.4 通過gather執(zhí)行并發(fā)請求 91
4.5 在請求完成時(shí)立即處理 95
4.6 使用wait進(jìn)行細(xì)粒度控制 99
4.6.1 等待所有任務(wù)完成 99
4.6.2 觀察異常 102
4.6.3 當(dāng)任務(wù)完成時(shí)處理結(jié)果 104
4.6.4 處理超時(shí) 107
4.6.5 為什么要將所有內(nèi)容都包裝在一個(gè)任務(wù)中 109
4.7 本章小結(jié) 110
第5 章 非阻塞數(shù)據(jù)庫驅(qū)動(dòng)程序 111
5.1 關(guān)于asyncpg 111
5.2 連接Postgres數(shù)據(jù)庫 112
5.3 定義數(shù)據(jù)庫模式 113
5.4 使用asyncpg執(zhí)行查詢 116
5.5 通過連接池實(shí)現(xiàn)并發(fā)查詢 119
5.5.1 將隨機(jī)sku插入products數(shù)據(jù)庫 119
5.5.2 創(chuàng)建連接池從而同時(shí)運(yùn)行查詢 123
5.6 使用asyncpg管理事務(wù) 128
5.6.1 嵌套事務(wù) 130
5.6.2 手動(dòng)管理事務(wù) 132
5.7 異步生成器和流式結(jié)果集 133
5.7.1 異步生成器介紹 134
5.7.2 使用帶有流游標(biāo)的異步生成器 135
5.8 本章小結(jié) 139
第6 章 處理CPU密集型工作 141
6.1 介紹multiprocessing庫 142
6.2 使用進(jìn)程池 144
6.3 進(jìn)程池執(zhí)行器與asyncio 146
6.3.1 進(jìn)程池執(zhí)行器 146
6.3.2 帶有異步事件循環(huán)的進(jìn)程池執(zhí)行器 148
6.4 使用asyncio解決MapReduce的問題 149
6.4.1 簡單的MapReduce示例 151
6.4.2 Google Books Ngram數(shù)據(jù)集 153
6.4.3 使用asyncio進(jìn)行映射和歸約 154
6.5 共享數(shù)據(jù)和鎖 159
6.5.1 共享數(shù)據(jù)和競爭條件 160
6.5.2 使用鎖進(jìn)行同步 163
6.5.3 與進(jìn)程池共享數(shù)據(jù) 166
6.6 多進(jìn)程,多事件循環(huán) 170
6.7 本章小結(jié) 173
第7 章 通過線程處理阻塞任務(wù) 175
7.1 threading模塊 176
7.2 通過asyncio使用線程 180
7.2.1 request庫 180
7.2.2 線程池執(zhí)行器 181
7.2.3 使用asyncio的線程池執(zhí)行器 183
7.2.4 默認(rèn)執(zhí)行器 184
7.3 鎖、共享數(shù)據(jù)和死鎖 186
7.3.1 可重入鎖 188
7.3.2 死鎖 190
7.4 單線程中的事件循環(huán) 192
7.4.1 Tkinter 193
7.4.2 使用asyncio和線程構(gòu)建響應(yīng)式UI 195
7.5 使用線程執(zhí)行CPU密集型工作 203
7.5.1 多線程與hashlib 203
7.5.2 多線程與NumPy 206
7.6 本章小結(jié) 208
第8 章 流 211
8.1 流 212
8.2 傳輸和協(xié)議 212
8.3 流讀取與流寫入 216
8.4 非阻塞命令行輸入 219
8.5 創(chuàng)建服務(wù)器 230
8.6 創(chuàng)建聊天服務(wù)器和客戶端 232
8.7 本章小結(jié) 239
第9 章 Web應(yīng)用程序 241
9.1 使用aiohttp創(chuàng)建REST API 242
9.1.1 什么是REST 242
9.1.2 aiohttp服務(wù)器基礎(chǔ)知識(shí) 243
9.1.3 連接到數(shù)據(jù)庫并返回結(jié)果 244
9.1.4 比較aiohttp和Flask 251
9.2 異步服務(wù)器網(wǎng)關(guān)接口 253
9.3 ASGI 與 Starlette 255
9.3.1 使用Starlette的REST端點(diǎn) 255
9.3.2 WebSocket與Starlette 257
9.4 Django異步視圖 261
9.4.1 在異步視圖中運(yùn)行阻塞工作 267
9.4.2 在同步視圖中使用異步代碼 268
9.5 本章小結(jié) 269
第10 章 微服務(wù) 271
10.1 什么是微服務(wù) 272
10.1.1 代碼的復(fù)雜性 272
10.1.2 可擴(kuò)展性 272
10.1.3 團(tuán)隊(duì)和堆棧獨(dú)立性 273
10.1.4 asyncio如何提供幫助 273
10.2 backend-for-frontend模式 273
10.3 實(shí)施產(chǎn)品列表API 275
10.3.1 用戶收藏服務(wù) 275
10.3.2 實(shí)現(xiàn)基礎(chǔ)服務(wù) 276
10.3.3 實(shí)現(xiàn)backend-for-frontend服務(wù) 281
10.3.4 重試失敗的請求 287
10.3.5 斷路器模式 290
10.4 本章小結(jié) 296
第11 章 同步 297
11.1 了解單線程并發(fā)錯(cuò)誤 298
11.2 鎖 302
11.3 使用信號(hào)量限制并發(fā)性 306
11.4 使用事件來通知任務(wù) 312
11.5 條件 317
11.6 本章小結(jié) 322
第12 章 異步隊(duì)列 323
12.1 異步隊(duì)列基本知識(shí) 324
12.1.1 Web應(yīng)用程序中的隊(duì)列 331
12.1.2 網(wǎng)絡(luò)爬蟲隊(duì)列 334
12.2 優(yōu)先級(jí)隊(duì)列 337
12.3 LIFO隊(duì)列 345
12.4 本章小結(jié) 347
第13章 管理子進(jìn)程 349
13.1 創(chuàng)建子進(jìn)程 349
13.1.1 控制標(biāo)準(zhǔn)輸出 352
13.1.2 同時(shí)運(yùn)行子進(jìn)程 355
13.2 與子進(jìn)程進(jìn)行通信 359
13.3 本章小結(jié) 363
第14章 高級(jí)asyncio 365
14.1 帶有協(xié)程和函數(shù)的API 366
14.2 上下文變量 368
14.3 強(qiáng)制事件循環(huán)迭代 370
14.4 使用不同的事件循環(huán)實(shí)現(xiàn) 371
14.5 創(chuàng)建自定義事件循環(huán) 373
14.5.1 協(xié)程和生成器 373
14.5.2 不建議使用基于生成器的協(xié)程 374
14.5.3 自定義可等待對象 376
14.5.4 使用帶有future的套接字 379
14.5.5 任務(wù)的實(shí)現(xiàn) 381
14.5.6 實(shí)現(xiàn)事件循環(huán) 383
14.5.7 使用自定義事件循環(huán)實(shí)現(xiàn)服務(wù)器 386
14.6 本章小結(jié) 388