• 正文
    • 為什么程序員總愛聊這些?
    • 第一章:進(jìn)程——程序界的「獨(dú)狼」
    • 第二章:線程——程序界的「同居情侶」
    • 第三章:協(xié)程——程序界的「時(shí)間管理大師」
    • 「三大門派」終極對(duì)比表(含「社死」現(xiàn)場(chǎng))
    • 高級(jí)彩蛋:「三者聯(lián)手搞事情」
    • 終極靈魂拷問
    • 一句話總結(jié)表
  • 相關(guān)推薦
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

進(jìn)程、線程、協(xié)程傻傻分不清?一文帶你徹底扒光它們的"底褲"!

03/26 14:00
282
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

各位程序員朋友(和假裝懂技術(shù)的同事): 如果你在面試時(shí)被問到:"請(qǐng)用奶茶店類比進(jìn)程、線程和協(xié)程",而你回答:"進(jìn)程是老板,線程是員工,協(xié)程是兼職..." ——恭喜你!你可能正在被面試官「祖安」?。▌e問我是怎么知道的??)

今天,我們不僅要搞懂這三者的關(guān)系,還要把它們扒得底褲都不剩!準(zhǔn)備好和我一起修煉「程序界解剖學(xué)」了嗎?


為什么程序員總愛聊這些?

因?yàn)樗鼈兙拖癯绦蚪绲摹溉龂?guó)演義」:

  • 進(jìn)程:曹魏政權(quán)(獨(dú)占資源,穩(wěn)如老狗)

  • 線程:孫劉聯(lián)軍(共享資源,相愛相殺)

  • 協(xié)程:諸葛亮北伐(一人帶十軍,靠的是「空城計(jì)」)


第一章:進(jìn)程——程序界的「獨(dú)狼」

定義:操作系統(tǒng)分配資源的最小單位,自帶「獨(dú)立戶口本」(虛擬地址空間)和「保鏢團(tuán)隊(duì)」(系統(tǒng)級(jí)資源)。

技術(shù)細(xì)節(jié)

  • 每個(gè)進(jìn)程都有自己獨(dú)立的內(nèi)存空間(就像你家的房子,別人不能隨便進(jìn))

  • 創(chuàng)建進(jìn)程的開銷≈在北京五環(huán)買套房(10ms~100ms)

  • fork() 系統(tǒng)調(diào)用是進(jìn)程的「克隆術(shù)」(但克隆出來的孩子和父母完全獨(dú)立)

職場(chǎng)類比 你開了一家奶茶店(主進(jìn)程),里面:

  • 水電費(fèi)(內(nèi)存)

  • 原料庫(kù)存(文件句柄)

  • 收銀臺(tái)POS機(jī)(CPU時(shí)間片) 如果奶茶店倒閉(進(jìn)程崩潰),隔壁的炸雞店(其他進(jìn)程)絕對(duì)不會(huì)受影響

經(jīng)典應(yīng)用場(chǎng)景

  • 微信后臺(tái)持續(xù)運(yùn)行(即使主界面關(guān)閉)

  • 銀行系統(tǒng)(必須嚴(yán)格隔離,你敢讓轉(zhuǎn)賬和取款共享內(nèi)存嗎?)


第二章:線程——程序界的「同居情侶」

定義:進(jìn)程內(nèi)的「共享公寓住戶」,共享地址空間但各有各的「私人日記本」(線程本地存儲(chǔ))。

技術(shù)細(xì)節(jié)

  • 線程切換成本≈在辦公室走動(dòng)(1μs~10μs)

  • 上下文切換時(shí)只需保存寄存器和棧指針(就像你下班時(shí)關(guān)燈、鎖門)

  • 死鎖風(fēng)險(xiǎn):兩個(gè)線程同時(shí)搶最后一塊披薩(資源競(jìng)爭(zhēng))

職場(chǎng)類比 奶茶店有3個(gè)員工(3個(gè)線程):

  • 收銀員(線程A):負(fù)責(zé)下單

  • 制作員(線程B):負(fù)責(zé)做奶茶

  • 外賣員(線程C):負(fù)責(zé)送外賣 他們共用:

  • 原料冰箱(共享內(nèi)存)

  • 工作臺(tái)(棧空間) 但不共享:

  • 自己的工牌(線程ID)

  • 心情日記(線程本地存儲(chǔ))

代碼示例Python多線程下載):

import threading
import time
?
def download(url, thread_name):
   start = time.time()
   print(f"{thread_name} 下載開始 {url}")
   time.sleep(2)  # 模擬下載耗時(shí)
   print(f"{thread_name} 下載完成 {url}, 耗時(shí) {time.time()-start:.2f}s")
?
threads = []
for i in range(5):
   t = threading.Thread(target=download, args=(f"http://example.com/file{i}", f"線程{i}"))
   threads.append(t)
   t.start()
?
for t in threads:
   t.join()
print("所有下載完成!")

輸出結(jié)果

markdown

線程0 下載開始 http://example.com/file0 ?
線程1 下載開始 http://example.com/file1 ?
...(并行執(zhí)行) ?
所有下載完成!

第三章:協(xié)程——程序界的「時(shí)間管理大師」

定義:用戶態(tài)的「虛擬線程」,靠主動(dòng)讓權(quán)(yield)實(shí)現(xiàn)協(xié)作,單線程內(nèi)玩出多任務(wù)的感覺。

技術(shù)細(xì)節(jié)

  • 協(xié)程切換成本≈打哈欠(0.1μs~1μs)

  • 阻塞操作會(huì)直接讓出CPU(比如等待網(wǎng)絡(luò)請(qǐng)求時(shí),自動(dòng)切換到其他協(xié)程)

  • 必須依附于線程(就像電動(dòng)車必須充電才能跑)

職場(chǎng)類比 你是個(gè)超級(jí)斜杠青年(主線程),同時(shí)干著:

  • 切水果(協(xié)程A)

  • 燒水(協(xié)程B)

  • 回復(fù)微信(協(xié)程C) 當(dāng)你切到一半發(fā)現(xiàn)水快開了(I/O事件),馬上扔下刀說:"我去關(guān)火!"( yield 控制權(quán))

代碼示例(Python異步爬蟲):

python

import asyncio
import aiohttp
?
async def fetch(url):
   async with aiohttp.ClientSession() as session:
       async with session.get(url) as response:
           return await response.text()
?
async def main():
   tasks = [fetch('http://example.com') for _ in range(10)]
   responses = await asyncio.gather(*tasks)
   print(f"抓取完成!共 {len(responses)} 條數(shù)據(jù)")
?
asyncio.run(main())

輸出結(jié)果

markdown

抓取完成!共 10 條數(shù)據(jù)

「三大門派」終極對(duì)比表(含「社死」現(xiàn)場(chǎng))

特性 進(jìn)程 線程 協(xié)程
資源開銷 高(買房) 中(合租) 低(睡沙發(fā))
切換成本 高(搬家) 低(換睡衣) 極低(眨眼)
隔離性 完全隔離(防剁手) 共享內(nèi)存(容易打架) 共享一切(但聽你話)
死鎖風(fēng)險(xiǎn) 無(獨(dú)居) 高(搶馬桶) 無(你說了算)
多核利用 是(每個(gè)進(jìn)程可以跑在不同CPU) 是(線程可以分配到不同核) 否(只能在一個(gè)核上蹦迪)
適用場(chǎng)景 銀行系統(tǒng)、docker容器 視頻渲染、實(shí)時(shí)音視頻 微信客服、高并發(fā)Web服務(wù)器
社死案例 進(jìn)程A崩了,進(jìn)程B說:"關(guān)我屁事!" 線程A和B互相鎖死,老板罵:"你們兩個(gè)能不能好好說話?" 協(xié)程C一直不yield,協(xié)程D喊:"大哥,給個(gè)機(jī)會(huì)啊!"

高級(jí)彩蛋:「三者聯(lián)手搞事情」

真實(shí)場(chǎng)景示例(Python + asyncio + 多線程):

python

import asyncio
import threading
from concurrent.futures import ThreadPoolExecutor
?
def cpu_bound_task(n):
   # 模擬CPU密集型任務(wù)
   return sum(i*i for i in range(n))
?
async def io_bound_task(url):
   # 模擬I/O密集型任務(wù)
   async with aiohttp.ClientSession() as session:
       async with session.get(url) as response:
           return await response.text()
?
async def main():
   # 線程池處理CPU任務(wù)
   with ThreadPoolExecutor() as executor:
       cpu_results = await asyncio.gather(
           *[asyncio.run_in_executor(executor, cpu_bound_task, 10**6)) for _ in range(10)]
       
   # 協(xié)程處理I/O任務(wù)
   io_results = await asyncio.gather(
       *[io_bound_task(f"http://example.com/{i}") for i in range(10)])
   
   print(f"CPU任務(wù)完成!耗時(shí):{time.time()-start:.2f}s")
   print(f"I/O任務(wù)完成!耗時(shí):{time.time()-start:.2f}s")
?
asyncio.run(main())

輸出結(jié)果

markdown

CPU任務(wù)完成!耗時(shí):0.50s ?
I/O任務(wù)完成!耗時(shí):0.15s

(這才是真正的「多核+異步」王炸組合!)


終極靈魂拷問

  1. 進(jìn)程和線程哪個(gè)是爹? → 進(jìn)程是操作系統(tǒng)生的,線程是進(jìn)程自己生的(親子鑒定:看虛擬地址空間)

  2. 協(xié)程能取代線程嗎? → 不能!協(xié)程適合I/O密集型,線程適合CPU密集型(就像火鍋和燒烤不能混搭)

  3. 用協(xié)程會(huì)不會(huì)更省電? → 是的!因?yàn)轭l繁切換協(xié)程比喚醒線程省電得多(手機(jī)續(xù)航黨狂喜)


一句話總結(jié)表

場(chǎng)景 進(jìn)程 線程 協(xié)程
寫代碼就像 開連鎖店 開分店共享倉(cāng)庫(kù) 在一家店當(dāng)多個(gè)兼職
系統(tǒng)資源消耗 大胃王 中等食量 節(jié)食達(dá)人
面試官看到你會(huì) 直接pass 給個(gè)及格分 大概率拿offer
性格特點(diǎn) 孤僻但靠譜 熱情但容易打架 高效但有點(diǎn)強(qiáng)迫癥

最后送大家一張「程序員認(rèn)親圖譜」:

markdown

操作系統(tǒng)(祖宗)
├── 進(jìn)程(兒子)
│ ? ├── 線程(孫子)
│ ? └── 其他資源(兒媳婦們)
└── 協(xié)程(私生子,爹是用戶自己)

下次在技術(shù)群里裝逼時(shí),記得甩出這張圖!保證讓非技術(shù)人員秒懂,讓同行直接給你遞煙??

相關(guān)推薦