來自:程序員小灰(微信號:chengxuyuanxiaohui)

來自:程序員小灰(微信號:chengxuyuanxiaohui)

————— 第二天 —————

————————————

什么是進(jìn)程和線程

有一定基礎(chǔ)的小伙伴們肯定都知道進(jìn)程和線程。

進(jìn)程是什么呢?

直白地講,進(jìn)程就是應(yīng)用程序的啟動實例。比如我們運(yùn)行一個游戲,打開一個軟件,就是開啟了一個進(jìn)程。

進(jìn)程擁有代碼和打開的文件資源、數(shù)據(jù)資源、獨立的內(nèi)存空間。

線程又是什么呢?

線程從屬于進(jìn)程,是程序的實際執(zhí)行者。一個進(jìn)程至少包含一個主線程,也可以有更多的子線程。

線程擁有自己的??臻g。

有人給出了很好的歸納:

對操作系統(tǒng)來說,線程是最小的執(zhí)行單元,進(jìn)程是最小的資源管理單元。

無論進(jìn)程還是線程,都是由操作系統(tǒng)所管理的。

Java中線程具有五種狀態(tài):

初始化

可運(yùn)行

運(yùn)行中

阻塞

銷毀

這五種狀態(tài)的轉(zhuǎn)化關(guān)系如下:

但是,線程不同狀態(tài)之間的轉(zhuǎn)化是誰來實現(xiàn)的呢?是JVM嗎?

并不是。JVM需要通過操作系統(tǒng)內(nèi)核中的TCB(Thread Control Block)模塊來改變線程的狀態(tài),這一過程需要耗費(fèi)一定的CPU資源。

進(jìn)程和線程的痛點

線程之間是如何進(jìn)行協(xié)作的呢?

最經(jīng)典的例子就是生產(chǎn)者/消費(fèi)者模式:

若干個生產(chǎn)者線程向隊列中寫入數(shù)據(jù),若干個消費(fèi)者線程從隊列中消費(fèi)數(shù)據(jù)。

如何用java語言實現(xiàn)生產(chǎn)者/消費(fèi)者模式呢?

讓我們來看一看代碼:

public class ProducerConsumerTest {

public static void main(String args[]) { final Queue<Integer> sharedQueue = new LinkedList(); Thread producer = new Producer(sharedQueue); Thread consumer = new Consumer(sharedQueue); producer.start(); consumer.start(); }

}

class Producer extends Thread {

private static final int MAX_QUEUE_SIZE = 5; private final Queue sharedQueue; public Producer(Queue sharedQueue) { super(); this.sharedQueue = sharedQueue; } @Override public void run() { for (int i = 0; i < 100; i++) { synchronized (sharedQueue) { while (sharedQueue.size() >= MAX_QUEUE_SIZE) { System.out.println("隊列滿了,等待消費(fèi)"); try { sharedQueue.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } sharedQueue.add(i); System.out.println("進(jìn)行生產(chǎn) : " + i); sharedQueue.notify(); } } }

}

class Consumer extends Thread {private final Queue sharedQueue;

public Consumer(Queue sharedQueue) { super(); this.sharedQueue = sharedQueue; } @Override public void run() { while(true) { synchronized (sharedQueue) { while (sharedQueue.size() == 0) { try { System.out.println("隊列空了,等待生產(chǎn)"); sharedQueue.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } int number = sharedQueue.poll(); System.out.println("進(jìn)行消費(fèi) : " + number ); sharedQueue.notify(); } } }

}

這段代碼做了下面幾件事:

1.定義了一個生產(chǎn)者類,一個消費(fèi)者類。

2.生產(chǎn)者類循環(huán)100次,向同步隊列當(dāng)中插入數(shù)據(jù)。

3.消費(fèi)者循環(huán)監(jiān)聽同步隊列,當(dāng)隊列有數(shù)據(jù)時拉取數(shù)據(jù)。

4.如果隊列滿了(達(dá)到5個元素),生產(chǎn)者阻塞。

5.如果隊列空了,消費(fèi)者阻塞。

上面的代碼正確地實現(xiàn)了生產(chǎn)者/消費(fèi)者模式,但是卻并不是一個高性能的實現(xiàn)。為什么性能不高呢?原因如下:

1.涉及到同步鎖。

2.涉及到線程阻塞狀態(tài)和可運(yùn)行狀態(tài)之間的切換。

3.涉及到線程上下文的切換。

以上涉及到的任何一點,都是非常耗費(fèi)性能的操作。

什么是協(xié)程

協(xié)程,英文Coroutines,是一種比線程更加輕量級的存在。正如一個進(jìn)程可以擁有多個線程一樣,一個線程也可以擁有多個協(xié)程。

最重要的是,協(xié)程不是被操作系統(tǒng)內(nèi)核所管理,而完全是由程序所控制(也就是在用戶態(tài)執(zhí)行)。

這樣帶來的好處就是性能得到了很大的提升,不會像線程切換那樣消耗資源。

既然協(xié)程這么好,它到底是怎么來使用的呢?

由于Java的原生語法中并沒有實現(xiàn)協(xié)程(某些開源框架實現(xiàn)了協(xié)程,但是很少被使用),所以我們來看一看python當(dāng)中對協(xié)程的實現(xiàn)案例,同樣以生產(chǎn)者消費(fèi)者模式為例:

這段代碼十分簡單,即使沒用過python的小伙伴應(yīng)該也能基本看懂。

代碼中創(chuàng)建了一個叫做consumer的協(xié)程,并且在主線程中生產(chǎn)數(shù)據(jù),協(xié)程中消費(fèi)數(shù)據(jù)。

其中 yield 是python當(dāng)中的語法。當(dāng)協(xié)程執(zhí)行到y(tǒng)ield關(guān)鍵字時,會暫停在那一行,等到主線程調(diào)用send方法發(fā)送了數(shù)據(jù),協(xié)程才會接到數(shù)據(jù)繼續(xù)執(zhí)行。

但是,yield讓協(xié)程暫停,和線程的阻塞是有本質(zhì)區(qū)別的。協(xié)程的暫停完全由程序控制,線程的阻塞狀態(tài)是由操作系統(tǒng)內(nèi)核來進(jìn)行切換。

因此,協(xié)程的開銷遠(yuǎn)遠(yuǎn)小于線程的開銷。

協(xié)程的應(yīng)用

有哪些編程語言應(yīng)用到了協(xié)程呢?我們舉幾個栗子:

Lua語言

Lua從5.0版本開始使用協(xié)程,通過擴(kuò)展庫coroutine來實現(xiàn)。

Python語言

正如剛才所寫的代碼示例,python可以通過 yield/send 的方式實現(xiàn)協(xié)程。在python 3.5以后,async/await 成為了更好的替代方案。

Go語言

Go語言對協(xié)程的實現(xiàn)非常強(qiáng)大而簡潔,可以輕松創(chuàng)建成百上千個協(xié)程并發(fā)執(zhí)行。

Java語言

如上文所說,Java語言并沒有對協(xié)程的原生支持,但是某些開源框架模擬出了協(xié)程的功能,有興趣的小伙伴可以看一看Kilim框架的源碼:

https://github.com/kilim/kilim

幾點補(bǔ)充:

1.關(guān)于協(xié)程的概念,小灰也僅僅是知道一些皮毛,希望小伙伴們多多指正。

2.本漫畫純屬娛樂,還請大家盡量珍惜當(dāng)下的工作,切勿模仿小灰的行為哦。

—————END—————

●編號717,輸入編號直達(dá)本文

算法與數(shù)據(jù)結(jié)構(gòu)

更多推薦《18個技術(shù)類公眾微信》

1.《漫畫:什么是協(xié)程?》援引自互聯(lián)網(wǎng),旨在傳遞更多網(wǎng)絡(luò)信息知識,僅代表作者本人觀點,與本網(wǎng)站無關(guān),侵刪請聯(lián)系頁腳下方聯(lián)系方式。

2.《漫畫:什么是協(xié)程?》僅供讀者參考,本網(wǎng)站未對該內(nèi)容進(jìn)行證實,對其原創(chuàng)性、真實性、完整性、及時性不作任何保證。

3.文章轉(zhuǎn)載時請保留本站內(nèi)容來源地址,http://f99ss.com/guoji/25206.html