Python【協程(Coroutine)和線程的關系】

????????協程(Coroutine)和線程都是實現并發編程的技術,但它們在實現方式、使用場景和性能上有顯著區別。理解它們的關系與差異有助于在實際應用中選擇合適的并發模型,以下是它們的核心關系與對比分析:

一、核心關系

  1. 互補關系
    協程和線程可以結合使用(如一個線程內運行多個協程,或多個線程各自運行協程)。

  2. 替代關系
    在I/O密集型場景中,協程常被用來替代線程以減少資源開銷。

  3. 層次關系
    協程是用戶態的"輕量級線程",線程是操作系統調度的基本單位。

生活化的比喻來解釋:快餐店點餐

線程版餐廳(傳統多線程)

  • 每個顧客(任務)配一個專屬服務員(線程)

  • 服務員A帶顧客1點餐 → 等廚師做漢堡(線程阻塞)

  • 服務員B帶顧客2點餐 → 等可樂機打飲料(線程阻塞)

  • 問題
    1個顧客發呆時,他的服務員只能干等著,不能服務其他人
    雇100個服務員(線程)成本太高(內存爆炸)

協程版餐廳(異步協程)

  • 1個超級服務員(事件循環)服務所有顧客

  • 帶顧客1點漢堡 → 記下"等3分鐘" → 立刻服務顧客2
    顧客2要可樂 → 記下"等1分鐘" → 檢查顧客1的漢堡好了沒...

  • 優勢
    1個服務員搞定全場!誰的食物好了就繼續服務誰

二、關鍵對比

特性協程 (Coroutine)線程 (Thread)
調度方用戶程序控制(事件循環)操作系統內核調度
切換成本極低(僅寄存器保存)高(需要內核態/用戶態切換)
內存占用通常KB級通常MB級(默認棧大小)
并發數量輕松支持數萬級通常數百到數千
并行能力單線程內并發,需多線程實現并行可利用多核CPU
阻塞影響一個協程阻塞會阻塞整個事件循環一個線程阻塞不影響其他線程
適用場景I/O密集型(網絡請求、文件讀寫等)CPU密集型或混合型任務
典型實現Python?asyncio、Go goroutinePython?threading、Java線程

生活化的比喻來解釋核心區別總結:

線程協程
員工雇傭大量服務員1個超人服務員
成本工資高(內存占用大)工資低(內存占用小)
效率經常站著等(阻塞)永遠在忙(非阻塞)
規模最多幾百人能接待數萬人

三、技術原理差異

1. 線程的實現

  • 內核調度:線程切換需要CPU從用戶態切換到內核態

  • 搶占式調度:操作系統決定何時切換線程

  • 同步問題:必須使用鎖等機制解決資源競爭

    # Python線程示例
    import threadingdef task():print("Thread running")thread = threading.Thread(target=task)
    thread.start()

2. 協程的實現

  • 用戶態調度:通過事件循環(Event Loop)管理

  • 協作式調度:協程主動讓出控制權(通過await

  • 單線程內并發:通過狀態保存/恢復實現

    # Python協程示例
    import asyncioasync def task():print("Coroutine running")asyncio.run(task())

四、典型協作模式

1. 單線程+多協程(經典異步模型)

async def fetch(url):print(f"Start fetching {url}")await asyncio.sleep(1)  # 模擬I/Oprint(f"Finished {url}")async def main():await asyncio.gather(fetch("url1"),fetch("url2")  # 兩個協程并發執行)asyncio.run(main())

輸出:

Start fetching url1
Start fetching url2
Finished url1
Finished url2

2. 多線程+每線程多協程(高并發服務)

async def handle_connection(reader, writer):data = await reader.read(100)writer.write(data)await writer.drain()async def thread_main():server = await asyncio.start_server(handle_connection, '127.0.0.1', 8888)async with server:await server.serve_forever()# 每個線程運行獨立的事件循環
def start_thread():asyncio.run(thread_main())threads = [threading.Thread(target=start_thread) for _ in range(4)]
for t in threads: t.start()

五、如何選擇?

使用協程當:

  • 需要高并發I/O操作(如Web服務器)

  • 希望減少內存開銷

  • 需要精細控制執行流程

  • 避免鎖的復雜性(單線程內協程無需鎖)

    使用線程當:

  • 需要利用多核CPU(計算密集型任務)

  • 調用阻塞式第三方庫(如某些數據庫驅動)

  • 需要操作系統級別的并行

    混合使用建議:

  • 用協程處理I/O密集型任務

  • 用線程池處理CPU密集型任務

  • 例如:FastAPI等框架使用線程池+協程的混合模式

現實場景
協程:適合網絡請求(比如同時爬1萬個網頁)
→ 就像服務員在等網頁響應時,可以先去處理其他請求

線程:適合計算任務(比如視頻轉碼)
→ 必須真的用多個廚師(CPU核心)同時干活

六、性能對比實驗

import asyncio
import threading
import time# 協程版本
async def coroutine_task(id):await asyncio.sleep(1)async def coroutine_main():tasks = [coroutine_task(i) for i in range(1000)]await asyncio.gather(*tasks)# 線程版本
def thread_task(id):time.sleep(1)def thread_main():threads = []for i in range(1000):t = threading.Thread(target=thread_task, args=(i,))t.start()threads.append(t)for t in threads: t.join()# 測試執行
start = time.time()
asyncio.run(coroutine_main())
print(f"Coroutines: {time.time()-start:.2f}s")start = time.time()
thread_main()
print(f"Threads: {time.time()-start:.2f}s")

輸出

Coroutines: 1.02s  # 1000個協程并發
Threads: 1.05s    # 1000個線程競爭資源

七、現代發展趨勢

  1. 協程成為主流:Go的goroutine、Python asyncio、Rust tokio等

  2. 線程角色轉變:更多作為協程的底層支撐(如CPU密集型任務)

  3. 混合編程模型

    • 使用協程處理高并發I/O

    • 使用線程池處理阻塞/計算任務

    • 使用多進程利用多核

理解兩者的關系和差異,能幫助開發者根據場景選擇最佳并發方案。

八、終極結論

  • 需要等別人(IO操作)時 → 用協程(省錢高效)

  • 需要真干活(CPU計算)時 → 用線程/進程(利用多核)

就像餐廳:
人多但都只是點單 → 1個超人服務員(協程)
真的要做100道菜 → 必須雇多個廚師(線程/進程)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/80487.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/80487.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/80487.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Springboot——Redis的使用

在當今的軟件開發領域,緩存技術是提升應用性能的關鍵手段之一。Redis 作為一款高性能的鍵值對存儲數據庫,憑借其出色的讀寫速度和豐富的數據結構,在緩存場景中得到了廣泛應用。Spring Boot 作為一款簡化 Spring 應用開發的框架,與…

BEVPoolv2:A Cutting-edge Implementation of BEVDet Toward Deployment

背景 該論文是在BEVDet的基礎上進行了一個調整優化,傳統的方法是將特征圖與深度預測進行外積得到視椎特征圖,再將它與預處理好的體素索引結合,將每個視椎特征分類到每個voxel中進行累加和的操作。BEVFusion與BEVDepth等方法是避免了累加和&a…

藍橋杯常考的找規律題

目錄 靈感來源: B站視頻鏈接: 找規律題具有什么樣的特點: 報數游戲(Java組): 題目描述: 題目鏈接: 思路詳解: 代碼詳解: 階乘求和(Java組…

使用ffmpeg 將圖片合成為視頻,填充模糊背景,并添加兩段音樂

1.輸入3張圖片,每張播放一次,播放兩秒,視頻分辨率設置為1920:1080,每張圖片前0.3秒淡入,后0.3秒淡出,圖片寬高比不變,用白色填充空白區域 ffmpeg -loop 1 -t 2 -i "img1.jpg" \-loop 1 -t 2 -i "img2.jpg" \-loop 1 -t 2 -i "img3.jpg" \-filte…

PostgreSQL技術內幕29:事件觸發器tag原理解析

文章目錄 0.簡介1.概念說明2.tag的生成和存儲2.1 tag合法性校驗2.2 內存中存儲2.3 持久化存儲 3.tag的觸發 0.簡介 在上一篇文章中中,我們介紹了PG中的兩種觸發器,即適合于DML的普通觸發器和對于DDL的事件觸發器,其中事件觸發器與常規的 DML…

mysql 導入很慢,如何解決

精選 原創 碼出財富2025-04-14 17:35:14博主文章分類:數據庫©著作權 文章標簽mysql數據庫用戶名文章分類MySQL數據庫yyds干貨盤點閱讀數184 導入大型 SQL 文件到 MySQL 數據庫時,速度可能會受到影響。以下是一些優化方法和建議,幫助你…

多物理場耦合低溫等離子體裝置求解器PASSKEy2

文章目錄 PASSKEy2簡介PASSKEY2計算流程PASSKEy2 中求解的物理方程電路模型等離子體模型燃燒模型 PASSKEy2的使用 PASSKEy2簡介 PASSKEy2 是在 PASSKEy1 的基礎上重新編寫的等離子體數值模擬程序。 相較于 PASSKEy1, PASSKEy2 在具備解決低溫等離子體模擬問題的能力…

保姆級zabbix監控jmx、數據庫和網絡監控(SNMP)

前言 在當今數字化時代,企業IT基礎設施的穩定性與性能直接關系到業務連續性和用戶體驗。隨著系統復雜性的不斷增加,單一維度的監控已難以滿足全面運維需求。Zabbix作為一款功能強大的開源監控解決方案,通過整合JMX(Java Manageme…

復雜地形越野機器人導航新突破!VERTIFORMER:數據高效多任務Transformer助力越野機器人移動導航

作者: Mohammad Nazeri 1 ^{1} 1, Anuj Pokhrel 1 ^{1} 1, Alexandyr Card 1 ^{1} 1, Aniket Datar 1 ^{1} 1, Garrett Warnell 2 , 3 ^{2,3} 2,3, Xuesu Xiao 1 ^{1} 1單位: 1 ^{1} 1喬治梅森大學計算機科學系, 2 ^{2} 2美國陸軍研究實驗室&…

SharpMap與TerraLib:C#與C++開源GIS庫

大家好,今天為大家介紹的軟件是SharpMap:一款專為了C#(.NET)環境設計的開源地圖和空間數據處理庫;TerraLib:一款由C編寫、支持多種數據庫的開源的GIS軟件庫。 下面,我們將從兩個開源軟件的主要…

音視頻學習 - MP3格式

環境 JDK 13 IDEA Build #IC-243.26053.27, built on March 16, 2025 Demo MP3Parser MP3 MP3全稱為MPEG Audio Layer 3,它是一種高效的計算機音頻編碼方案,它以較大的壓縮比將音頻文件轉換成較小的擴展名為.mp3的文件,基本保持源文件的音…

Unity中數據和資源加密(異或加密,AES加密,MD5加密)

在項目開發中,始終會涉及到的一個問題,就是信息安全,在調用接口,或者加載的資源,都會涉及安全問題,因此就出現了各種各樣的加密方式。 常見的也是目前用的最廣的加密方式,分別是:DE…

部署本地deepseek并在調用的詳細步驟以及解決一些可能出現的問題(Windows,Linux, WSL)

打開Ollama官網:https://ollama.com/ 直接下載Ollama并且安裝好Ollama、這時候就能看到app里多了個ollama,但是我們不用打開它 打開Windows Powershell: ollama run deepseek-r1:1.5b 7b 8b 14b 32b 70b 根據自己的電腦配置和需求更換不同的…

【KWDB 創作者計劃】_嵌入式硬件篇---寄存器與存儲器截斷與溢出

文章目錄 前言一、寄存器與存儲器1. 定義與基本概念寄存器(Register)位置功能特點存儲器(Memory)位置功能特點2. 關鍵區別3. 層級關系與協作存儲層次結構協作示例4. 為什么需要寄存器性能優化指令支持減少總線競爭5. 其他寄存器類型專用寄存器程序計數器(PC)棧指針(SP)…

小白自學python第二天

學習python的第二天 一、判斷語句 1、布爾類型和比較運算符 1、布爾類型 表示現實生活中的邏輯,真(True,用數字1表示)和假(False,用數字0表示) 2、布爾類型變量的定義 變量的名稱 布爾類…

linux基礎操作1------(文件命令)

一.前言 我們本章開始講解linux,我們對于linux得有重要的認識,比如項目部署等等,都會用到linux,今天我們就開始linux的學習,我們需要準備的工具有vmware和xshell,而這里我就不教大家虛擬機的安裝以及xshel…

編碼問題整合

一、windows系統編碼 查看編碼命令:chcp - 936 GBK - 65001 UTF-8 - 437 英文修改系統編碼 1、控制面板修改 需管理員權限-Windows 10/11進入 控制面板 > 區域 > 管理 > 更改系統區域設置勾選 Beta版: 使用Unicode UTF-8提供全球語言支持 → 重啟生效修…

如何配置Spark

1.上傳spark安裝包到某一臺機器(自己在finaShell上的機器)。 2.解壓。 把第一步上傳的安裝包解壓到/opt/module下(也可以自己決定解壓到哪里)。對應的命令是:tar -zxvf 安裝包 -C /opt/module 3.重命名。進入/opt/mo…

Redis 完整配置模板

一、基礎連接配置(單機模式) 基礎參數(適用Spring Boot) spring:redis:host: 127.0.0.1port: 6379password: your_passworddatabase: 0 # 默認DB索引timeout: 2000ms # 全局操作超時時間二、連接池參數(通用核心配…

邊界凸臺建模與實例

文章目錄 邊界凸臺特征耳機案例瓶子 邊界凸臺特征 兩側對稱拉伸最上面的圓柱 同過兩點一基準面畫草圖,在基準面上畫橢圓 隱藏無關的實體和草圖,以便橢圓的端點能與線給穿透約束,下面的點與下面的線也給穿透,短軸長給35&#xff08…