(大部分為翻譯)
Concurrency vs. Parallelism 併發 vs 並行
併發並不一定同時執行,比如使用時間片,使得兩個任務交替執行。而並行是執兩個任務真正的同時執行。
Asynchronous vs. Synchronous 同步 vs 非同步
如果一個方法被呼叫後,呼叫者只能等到此方法返回值或丟擲異常才能繼續前進,那這個方法就被稱為是“同步”的。
而“非同步”呼叫,是指呼叫者在經歷有限的步驟之後,可以繼續前進。方法的完成可以通過其它的機制進行通知,比如Callback, Future, 或者訊息。
一個同步的API可以使用阻塞來實現同步,但這不是必須的。比如一個CPU密集型的任務的行為會類似於阻塞。通常,使用非同步API更好,因為它能保證系統能夠繼續前進下去。Actor在本質上是非同步的: Actor在傳送完一個訊息以後會繼續執行,而不用等到訊息真的投遞出去。
Non-blocking vs. Blocking 阻塞 vs. 非阻塞
阻塞是說一個執行緒可以無限期地延遲另一個執行緒的執行。比如使用互拆鎖。非阻塞是說沒有執行緒能夠無限地阻塞其它執行緒。
Deadlock vs. Starvation vs. Live-lock 死鎖、飢餓、活鎖
死鎖是說一些參與者互相等待其它人到達一個指定的狀態,這樣它們才能前進。但是在其它人到達一個指定狀態前,沒有任何一個能前進,所以所有受影響的子系統都停止了。死鎖和“阻塞”緊密聯絡,因為發生死鎖必須得是一個參與者執行緒能夠無限阻塞其它執行緒前進。
在死鎖狀態下,沒有任保一個參與者能夠前進。但是飢餓卻是有些參與者能前進,但是有些就不能。比如優先順序排程演算法時,如果高優先順序的任務特別多,低優先順序的就永遠輪不到執行。
活鎖和死鎖有些類似,在於沒有任何參與者能前進。但是這些參與者的狀態的確是在改變,而不是由於互相等待而永遠不變。一個活鎖發生的情形是:兩個參與者互相檢測對方的狀態,來獲取兩個資源中的一個。當它們中的一個檢測到另一個也想獲取同一個資源時,就放棄當前這個,試圖去獲取另一個。這樣,它們可能恰巧總是想獲取同一個,於是它們就“活鎖”了。
RaceCondition 競態
當我們對一些事件的順序的推測會受到外部的不可預測的影響時,這種情況就叫做“競態”。一個典型的情形是,一些執行緒共享狀態。這樣執行緒交替執行,會產生非預期的行為。但是共享狀態對於競態不是必須的,比如通過UDP傳送包時,包傳送的順序和接收的順序可能是亂的。這樣,如果單獨的包不包含順序的資訊,server端就無法確定它們的傳送順序。這樣就是一種競態。
在兩個actor之前傳送訊息時,Akka保證訊息傳送的順序會被保留。
Non-blocking Guarantees ( Progress Conditions)
正如前邊所討論的,阻塞是我們所不希望的,因為它可能導致死鎖,並且降低了系統的吞吐量。下邊我們討論不同的非阻塞性質,這些非阻塞性有不同的強度。
Wait-freedom
如果對一個方法的每次呼叫在有限的步驟內都能完成,這個方法就被稱為"wait-free". If a method is bounded wait-free, then the number of steps has a finite upper bound.
wait-free的方法永遠不會阻塞,從而不會發生死鎖。從另一個角度來看,由於對方法的呼叫在有限的步驟內會結束,因此呼叫者在呼叫結束後會前進,因此也不會有飢餓。
Lock-freedom
Lock-freedom 比wait-freedom更弱。對於lock-free的方法呼叫,在絕大多數情況下都會在有限步驟後結束。所以對lock-free呼叫,死鎖是不可能的。但是飢餓是可能的,因為並不能保證所有的呼叫最終都會結束。
Obstruction-freedom
Obstruction-freedom是最弱的非阻塞保證。
如果一個方法有機會在一個時間點後單獨執行(其它執行緒不再被執行),那它就會在有限的幾步內結束,那這個方法就是obstruction-freedom。所有lock-free的物件都是obstruction-free的,但反過來就不成立了。