要理解generator就必須知道一個概念,那就是協程
。javascript
協程,又成爲微線程(coroutine)。html
進程(process) vs 線程(thread)java
咱們都知道在操做系統級別上有兩個重要的概念(也是實體):進程(process)和線程(thread),這兩個東西是用於操做系統模擬並行
的,在單個CPU上,os經過調度算法,讓CPU輪流執行線程或者進程,來達到程序的併發執行。node
那麼協程又是什麼?首先要明確的是,協程是編譯器級別的,而並不是線程和進程同樣是操做系統級別的。協程的實現,經過是對某個語言作相應的提議,而後經過後成編譯器標準,而後編譯廠商來實現該機制。git
協程的做用是什麼?github
簡單來講,就是實現函數的分段式執行。就是一個函數的執行能夠主動放棄CPU的控制權,先掛起,讓其餘的函數先執行,而後在返回,從上次執行結束的地方繼續執行。算法
這樣看起來很像是多線程輪流執行。可是卻有着很大的區別:協程是一個線程執行
。編程
由於是一個線程執行,因此不存在線程的切換,而是由程序自身控制,也就不存在所謂的線程切換的開銷。安全
不須要多線程的鎖機制。由於只有一個線程,也就不存在同時寫變量的衝突。在協程中控制共享資源不加鎖,只須要判斷狀態就行了。這也說明協程的執行效率很高一些。網絡
舉個生產者消費者模型基於搶佔式多線程編程
的實現(僞代碼)
// 資源,隊列容器 var q = []; // 消費者進程 loop(); // 循環等待 lock(q); // 加鎖 var item = getResourceFrom(q); // 獲取資源 unlock(q); // 操做結束,資源解鎖 operatingResource(item); sleep; // 生成者線程 loop(); // 循環等待 var item = createResource(p); // 生產資源 lock(q); // 加鎖 q.push(item); // 寫入資源 unlock(q); // 解鎖
能夠看到,以上的代碼中有兩個特色
對資源操做須要進行加鎖和解鎖的操做。(保證線程安全)
消費者線程必須經過sleep,讓出CPU,用於執行生產者線程使用。
那麼若是是協程的編程模式,就簡單地多。
var q = []; var count = 0; // 消費者 function *consumer() { while (true){ var item = yield producer(); console.log(item); } } // 生產者 function producer() { q.push(count++); } function main () { const consumerGen = consumer(); // 咱們能夠經過代碼來控制其交替執行 // 執行到獲取item以前,放棄執行權,先執行producer(), consumerGen.next(); // 以後能夠獲取item,而後再放棄執行權,執行producer,一直循環 consumerGen.next(q.shift()); // 0 consumerGen.next(q.shift()); // 1 consumerGen.next(q.shift()); // 2 consumerGen.next(q.shift()); // 3 consumerGen.next(q.shift()); // 4 consumerGen.next(q.shift()); // 5 } main();