徹底理解:阻塞、非阻塞、同步、異步、Reactor、Proactor

我以前是寫AS3的,事件和回調無處不在,天生就是異步的,很少需要討論這些概念。現在寫C#,這些概念提的就多了,所以需要徹底搞明白。如果把技術的邏輯抽象出來,跟生活中的邏輯做比較,你會發現技術包含的道理是多麼的樸素呀。

本程序中的代碼大部分是示意代碼,不能真正運行。

1、阻塞:阻塞是指當前線程被堵住了,不能繼續往下執行了,就被操作系統掛起了。

阻塞的對象是當前線程,而不是IO被阻塞了;外部資源(通常是IO)使得當前線程被掛起才叫阻塞,內部程序執行的再慢也不叫阻塞,比如一個JPEG.Encode(),雖然這個函數的執行很慢,但它仍然在執行,不叫阻塞。阻塞的核心表現是等待,什麼事情都做不了,只有等待。

2、非阻塞:調用外部資源,不管結果如何,不會阻擋線程的繼續執行。

3、同步:“調用”然後得到“結果”。可能立即得到結果,可能等待一毫秒,也可能等待一輩子,反正結果必須緊隨其後。

同步的概念關鍵在於結果必須緊隨調用者之後到來,可以有等待,也可以沒有等待,不管有沒有等待,同步跟阻塞都沒有必然關係。比如同步非阻塞接口Socket.NoBlockRecv(),一旦調用它,有數據就返回數據,沒數據就返回空數據或錯誤,反正不會讓你等待。

還有一個同步非阻塞的例子是協程,協程是一種巧妙的機制,既實現了同步返回結果(不像Socket.NoBlockRecv()沒有數據就返回空數據或錯誤當結果),又不會阻塞當前線程。下面是Unity3D的協程的例子:

   IEnumerator WaitAndDebug()
    {
          //打印一句日誌
        Debug.Log("WaitAndDebug start" + Time.time);
        //這句的執行要花費5秒,但5秒時間段內,當前線程可以幹其它事,同步非阻塞。
        yield return new WaitForSeconds(5);
        //5秒後再打印一句日誌
        Debug.Log("WaitAndDebug done" + Time.time);
    }

4、異步:“調用”,有“結果”再通知我。異步跟同步的區別是,結果返回時間點跟調用發起時間點沒有強制關係,調用者是被動得到結果的,不是主動等待結果的。

5、Reactor:響應模式,我是被動的,外部要我幹什麼,我就幹什麼,受外部驅動。Reactor模式雖然起源於網絡IO設計,但這種思想是通用的。基於Reactor模式的網絡IO是這樣的:

首先聲明要監聽哪些事件
socket.addEventHandler("receiveEvent",  receiveHandler);
socket.addEventHandler("canSendEvent",  canSendHandler);

function receiveHandler()
{
     socket.receive();//IO告訴我有數據來了,我纔去接收數據,同步的
}

function canSendHandler()
{
     socket.send();//IO告訴我它不繁忙了,可以發送數據了,我纔去發數據,同步的
}

Reactor的核心是被動響應,程序響應IO事件,具體的收發操作還是需要程序自己去完成,雖然這期間沒有阻塞,但收發操作還是同步的。

6、Proactor:主動模式,我是主動的,我想什麼時候幹,就什麼時候幹,不受外部驅動。基於Proactor模式的網絡IO是這樣的:

socket.addEventHandler("receiveSuccessEvent",  receiveSuccessHandler);
socket.addEventHandler("sendSuccessEvent", sendSuccessHandler);

//不用關心IO是否繁忙,發就是了,成功了會通知我的,通過sendSuccessEvent事件
socket.sendAsync(data);
//不用關心有沒有數據,我想何時接收就接收,如果我不執行接收,就永遠不會觸發receiveSuccessEvent事件
socket.receiveAsync();

function receiveSuccessHandler(data)
{
    log("received data");//IO已經把數據接收好了,然後通知我,異步的
}

function sendSuccessHandler()
{
     log("send data success");//IO把數據發送成功了,然後通知我,異步的
}

舉個形象的例子:去銀行取款。
Reactor:拿號,某個櫃檯空閒了就通知我去取款,我還是必須坐到櫃檯前取款,取款過程還是同步的。
Proactor:拿號,告訴大堂經理我要取款,款到了,大唐經理送到我手中,取款過程是異步的。

以上都是個人理解,如果有錯誤的地方,歡迎大家指正。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章