在Appium1.7.1里集成了一個同步模塊async-lock用來支持多會話功能。
只能說就算是以單線程高並發聞名的I/O密集型Nodejs也不得不擴展額外的同步塊方法,或者說,在現有的計算機體系結構和配備的操作系統之下,所有的編程語言都無法摒棄同步信息塊。
不過想想也是,這個世界原本是處於無序的狀態,只是有了人類的干預,才會讓一切事情直着走。要是沒有同步塊,所有的線程(Nodejs底層的異步也是多線程)就會如野草生成一般,力量強大,但不可被控制,而不可被控制恰恰是不能被人類所容忍的。
首先需要明白一點的是,或者說以下內容的前提是,Nodejs碰到異步回調會啟動I/O,之后繼續往下執行。
以官網的兩句代碼(https://www.npmjs.com/package/async-lock)為例:
user1和user1操作redis數據庫,取同一個鍵的值乘以2:
User1 lock.acquire('key', function(cb){ // Concurrency safe redis.get('key', function(err, value){ redis.set('key', value * 2, cb); }); }, function(err, ret){ });
User2 lock.acquire('key', function(cb){ // Concurrency safe redis.get('key', function(err, value){ redis.set('key', value * 2, cb); }); }, function(err, ret){ });
acquire函數的簽名如下:
AsyncLock.prototype.acquire = function (key, fn, cb, opts)
key:就是”key”
fn:就是執行的函數
cb:fn函數執行完后的回調函數
opts:配置參數
再看acquire函數的具體實現
對於User1,進入acquire函數執行的是:
這里是個關鍵:queue是一個字典型,一開始key為空,queue[‘key’]已經被賦值空數組了,執行exec(true)函數。
exec函數:
if else判斷需要返回的是Promise,還是以函數回調的方式結束
User1、User2的例子是函數回調方式,所以進入if條件執行。
cb是fn(cb)傳過來的,在執行完fn()函數后,就會調用cb:
這里是重點,在調用fn之前,都是CPU在執行,現在執行fn函數,會有回調,這個時候異步I/O啟動,CPU繼續往下執行,這里的CPU往下執行不是進入fn函數體,而是執行User2的代碼,即開始執行:
還是進入acquire函數,這個時候走的是另一個分支:
把exec函數存進一個數組,然后User2就執行完了。CPU繼續往下執行User2之后的代碼。
假如在某個時刻,User1的異步執行到了cb函數,即紅框內的函數:
會調用done函數,其中的關鍵如下:
可以看到,User2被移出,並且執行其中的exec函數,這樣就能保證User2的異步代碼在User1之后執行。
總結起來,是以一個中間共有的隊列,存放異步函數,在上一個操作完臨界資源后,再從隊列里shift出來執行異步函數,以達到同步的目的。