進程、線程、異步

行文綱目
(一)進程、線程
(二)事件驅動
(三)異步與線程的關係

javascript

(一)進程、線程
英文    中文       類比
cpu    中央處理器    工廠(電力有限,單一時刻只供一個車間使用)
process  進程(任務)   車間(有各類資源,機牀、餐廳、臥室、廁所)
thread   線程(子任務)  工人(可使用車間資源,來完成各自子任務)html

  進程是系統分配的獨立資源,是 CPU資源分配的基本單位,進程是由一個或者多個線程組成的。一個cpu任意時刻,只能運行一個進程。
  線程是進程的執行流,是CPU調度和分派的基本單位,同個進程之中的多個線程之間是共享該進程的資源的。
  互斥鎖(Mutual exclusion,縮寫 Mutex),保障單一時間內,只有1個線程操做某塊共享內存,等這個線程退出,外面線程方可進入。相似mysql中的排它鎖。
  信號量(Semaphore),保障單一時間內,最多n個線程操做某塊共享內存,釋放幾個,才能夠再進入幾個。相似mysql的共享鎖。java

    操做系統的設計,所以能夠歸結爲三點:
(1)以多進程形式,容許多個任務同時運行;
(2)以多線程形式,容許單個任務分紅不一樣的部分運行;
(3)提供協調機制,一方面防止進程之間和線程之間產生衝突,另外一方面容許進程之間和線程之間共享資源。node

(參考http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html)
mysql

(二)事件驅動sql

    事件隊列(Event Queue)
    異步會進入Event Table,等待回調條件知足時,推入Event Queue,這時,主線程若執行完畢,會將回調拉入主線程執行瀏覽器

event-queue.jpg

    注:若是主線程中的同步代碼很是多,執行須要很長時間,會致使異步隊列中,達到執行條件的回調沒法及時執行,只有主線程任務結束纔會執行Event Queue中存在的回調。bash

    事件循環(Event Loop)
    宏任務和微任務切換執行,不斷循環,造成了事件循環。 瀏覽器執行script的過程以下:網絡

event-loop.jpg

宏任務 Macrotask 有哪些?多線程

HTML parsing、Network events、Mouse events、Keybord events、setTimeout、setInterval

微任務 Microtask 有哪些?

process.nextTick、Promise.then、Promise.catch、Promise.finally、DOM mutations

判斷如下代碼,在node中的輸出結果

// 主線程直接執行
console.log(1);
// 放入宏事件隊列中
setTimeout(function() {
    console.log(5);
    new Promise(function(resolve) {
        console.log(6);
        resolve();
    }).then(function() {
        console.log(8)
    })
    process.nextTick(function() {
      console.log(7);
    })
})
// 微任務
process.nextTick(function() {
    console.log(3);
})
// 主線程直接執行
new Promise(function(resolve) {
    console.log(2);
    resolve();
}).then(function() {
    // 微任務
    console.log(4)
})
複製代碼

輸出順序就是數字自己。注意:同爲微任務,process.nextTick會在Promise.then以前哦
(參考自一篇網絡文章,具體記不清了)

(三)異步與線程的關係

function foo() {
    console.log( 'first' );
    setTimeout( ( function(){ console.log( 'second' ); } ), 5);
 
}
 
for (var i = 0; i < 1000000; i++) {
    foo();
}
複製代碼

    執行結果會首先所有輸出first,而後所有輸出second;儘管中間的執行會超過5ms。爲何?

    前面已經提到瀏覽器是事件驅動的(Event driven),瀏覽器中不少行爲是異步(Asynchronized)的,例如:鼠標點擊事件、窗口大小拖拉事件、定時器觸發事件、 XMLHttpRequest完成回調等。當一個異步事件發生的時候,它就進入事件隊列。瀏覽器有一個內部大消息循環,Event Loop(事件循環),會輪詢大的事件隊列並處理事件。例如,瀏覽器當前正在忙於處理onclick事件,這時另一個事件發生了(如:window onSize),這個異步事件就被放入事件隊列等待處理,只有前面的處理完畢了,空閒了纔會執行這個事件。setTimeout也是同樣,當調用的時 候,js引擎會啓動定時器timer,大約xxms之後執行xxx,當定時器時間到,就把該事件放到主事件隊列等待處理(瀏覽器不忙的時候纔會真正執 行)。

    每一個瀏覽器具體實現主事件隊列不盡相同,這不談了。

    瀏覽器不是單線程的     雖然JS運行在瀏覽器中,是單線程的,每一個window一個JS線程,但瀏覽器不是單線程的,例如Webkit或是Gecko引擎,均可能有以下線程:

javascript引擎線程
界面渲染線程
瀏覽器事件觸發線程
Http請求線程

    不少童鞋搞不清,若是js是單線程的,那麼誰去輪詢大的Event loop事件隊列?答案是瀏覽器會有單獨的線程去處理這個隊列。

    AJAX請求是否真的異步?   其實請求確實是異步的,這請求是由瀏覽器新開一個線程請求(見前面的瀏覽器多線程)。當請求的狀態變動時,若是先前已設置回調,這異步線程就產生狀態變動事件放到 JavaScript引擎的事件處理隊列中等待處理。當瀏覽器空閒的時候隊列任務被處理。javascript引擎確實是單線程處理它的任務隊列,能理解成就是普通函數和回調函數構成的隊列。

    總結一下,Ajax請求確實是異步的,這請求是由瀏覽器新開一個線程請求,事件回調的時候是放入Event loop單線程事件隊列等候處理。

    setTimeout(func, 0)爲何有時候有用?
    寫 js多的童鞋可能發現,有時候加一個setTimeout(func, 0)很是有用,爲何?難道是模擬多線程嗎?錯!前面已經說過了,javascript是JS運行在瀏覽器中,是單線程的,每一個window一個JS線 程,既然是單線程的,setTimeout(func, 0)神奇在哪兒?那就是告訴js引擎,在0ms之後把func放到主事件隊列中,等待當前的代碼執行完畢再執行,注意:重點是改變了代碼流程,把func 的執行放到了等待當前的代碼執行完畢再執行。這就是它的神奇之處了。它的用處有三個:

1.讓瀏覽器渲染當前的變化(不少瀏覽器UI render和js執行是放在一個線程中,線程阻塞會致使界面沒法更新渲染)
2.從新評估」script is running too long」警告
3.改變執行順序

    例如:下面的例子,點擊按鈕就會顯示"calculating....",若是刪除setTimeout就不會。由於reDraw事件被進入事件隊列到長時間操做的最後才能被執行,因此沒法刷新。

<button id='do'> Do long calc!</button>
<div id='status'></div>
<div id='result'></div>
 
 
$('#do').on('click', function(){
  
  $('#status').text('calculating....'); //此處會觸發redraw事件的fired,但會放到隊列裏執行,直到long()執行完。
  
  // without set timeout, user will never see "calculating...."
  //long();//執行長時間任務,阻塞
   
  // with set timeout, works as expected
  setTimeout(long,50);//用定時器,大約50ms之後執行長時間任務,放入執行隊列,但在redraw以後了,根據先進先出原則
  
 })
  
  
  
function long(){
  var result = 0
  for (var i = 0; i<1000; i++){
    for (var j = 0; j<1000; j++){
      for (var k = 0; k<1000; k++){
        result = result + i+j+k
      }
    } 
  }
  $('#status').text('calclation done') // has to be in here for this example. or else it will ALWAYS run instantly. This is the same as passing it a callback 
}
複製代碼

(參考https://www.cnblogs.com/yasmi/articles/5064588.html)

相關文章
相關標籤/搜索