簡體   English   中英

Node.js異步任務是否同步處理?

[英]Are Node.js asynchronous tasks handled synchronously?

考慮以下代碼:

var some_expensive_task = function(i) {
    setTimeout(function() {
        var a = 1;

        while (a < 100000000) {
            Math.sqrt(a);

            ++a;
        }
        console.log('finished set' + i);
    }, 0);
};

for (var i = 0; i < 70; ++i) {
    console.log('start ' + i);
    some_expensive_task(i);
    console.log('end ' + i);
}

該程序的目的是使用setTimeout迭代並啟動70個CPU密集型異步任務。

正如所料,該計划的產出是:

start 1
end 1
...
start 69
end 69
finished set1
...
finished set69

在整個執行過程中,只有兩個過程。 我假設其中一個是空閑事件循環,另一個是100%運行的工作進程。

我是否正確理解當事件循環同步執行時,啟動的異步任務(無論來源如何)都按照調用它們的順序同步執行?

UPDATE

我仍然覺得我沒有把我的問題清楚地表達出來。 使用setTimeout是我能想到的准確安排一堆異步函數運行的唯一方法。 我想真正的問題是,如果我用setTimeout啟動三個異步函數,仍然是零延遲,是第二個我開始保證在第一個完成后運行,第三個保證在第二個完成后啟動嗎?

你在問題中使用了不正確的術語, Are Node.js asynchronous tasks handled synchronously沒有多大意義。 測試用例不是你想象的那樣。 首先明確一些術語:

保證同步函數按其調用順序運行/完成。

異步函數可以在調用時進行並完成無序操作。

阻止操作是指一旦啟動就必須完成的操作,以便執行進一步發展。 除非在單獨的worker上運行,否則CPU密集型操作將被阻止。 循環本質上是阻塞的。 一旦它們啟動,它們將在執行下一個函數之前完成所有迭代。

setTimeout在當前時間之后至少調用傳遞函數至少x ms。 調用它意味着一旦x ms通過它就會在事件循環中對傳遞的函數進行排隊。 這只是延遲執行。

因此,考慮到上述事實,這就是為什么您的測試具有誤導性的原因:

  • 首先,您的測試用例(您的CPU密集型函數)不是異步的,您將它包裝在異步的setTimeout周圍。 超時0僅表示它們將按照調用它們的順序執行。 所有回調函數都是同步的。

  • 其次,日志中的開始和結束表示調用setTimeout的位置。 這將按預期順序進行。 超時0時,完成也將按順序完成。 是的,如果你保持超時等於他們,他們將按照通過的順序執行。 然后,這是許多可能的情況之一,其中結果類似於同步(如果超時按遞增順序怎么辦?)。 你問的問題可能適用於這些情況,但並非總是如此。

  • 第三,如果你想模擬異步性(足以看到控制台上的無序行為),可以放松while循環並使用隨機超時( Math.random()*1000 )。 你會看到它們以任意方式完成。 這將是異步執行(setTimeout而不是回調)。

Node.js是單線程的,並且在一個進程中運行,因為JavaScript是單線程的。 因此你是對的。

是。 Javascript,包括NodeJS,是單線程的(除了少數例外)。

當您使用setTimeout(fn, 0) ,它會將當前調用堆棧清除后運行的函數排隊。 在您的示例中,這意味着for循環將在“昂貴的任務”運行之前完成。

您的JS代碼在Node.js中的單個線程中運行。 所有其他本機Node.js API都是用C / C ++編寫的,可以是異步的,也可以在單獨的線程上運行。 有關更詳細的說明,請參閱此答案

我是否正確理解當事件循環同步執行時,啟動的異步任務(無論來源如何)都按照調用它們的順序同步執行?

是的,你是對的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM