1.1. I/O編程模型淺析
服務器端編程經常需要構造高性能的IO模型,常見的IO模型有四種:
(1)同步阻塞IO(Blocking IO):即傳統的IO模型。
(2)同步非阻塞IO(Non-blocking IO):默認創建的socket都是阻塞的,非阻塞IO要求socket被設置為NONBLOCK。
(3)IO多路復用(IO Multiplexing):即經典的Reactor設計模式,有時也稱為異步阻塞IO,Java中的Selector和Linux中的epoll都是這種模型。
(4)異步IO(Asynchronous IO):即經典的Proactor設計模式,也稱為異步非阻塞IO。
同步和異步的概念描述的是用戶線程與內核的交互方式:
-
同步是指用戶線程發起IO請求后需要等待或者輪詢內核IO操作完成后才能繼續執行;
-
異步是指用戶線程發起IO請求后仍繼續執行,當內核IO操作完成后會通知用戶線程,或者調用用戶線程注冊的回調函數。
阻塞和非阻塞的概念描述的是用戶線程調用內核IO操作的方式:
-
阻塞是指IO操作需要徹底完成后才返回到用戶空間;
-
非阻塞是指IO操作被調用后立即返回給用戶一個狀態值,無需等到IO操作徹底完成。
1.2. 同步阻塞I/O
同步阻塞I/O模型是最簡單的I/O模型,用戶進程在進行I/O操作時被阻塞,如下圖所示:
在ASP.NET Core中沒有使用多線程或加入異步關鍵字的模型均為同步阻塞I/O
public IActionResult Sync()
{
var start = DateTime.Now;
Add();
return Json("start:"+start+"||| end:" + DateTime.Now);
}
void Add()
{
Thread.Sleep(2000);
Console.WriteLine(DateTime.Now);
}
1.3. 同步非阻塞I/O
在同步非阻塞整個IO請求的過程中,雖然用戶線程每次發起IO請求后可以立即返回,但是為了等到數據,仍需要不斷地輪詢、重復請求,消耗了大量的CPU的資源。一般很少直接使用這種模型,而是在其他IO模型中使用非阻塞IO這一特性
在ASP.NET Core 中可以使用多線程來實現同步非阻塞,在如下代碼清單中可以看到,使用多線程調用一個會自動休眠2秒的方法,主線程Sync
會先返回值,而不會阻塞。
public IActionResult Sync()
{
var thread = new Thread(new ThreadStart(this.Add));
thread.Start();
return Json(DateTime.Now);
}
void Add()
{
Thread.Sleep(2000);
Console.WriteLine(DateTime.Now);
}
而子線程由於被阻塞了2秒,因此時間為:
如果想在同步非阻塞的情況下獲得返回的數據,就需要輪詢,重復的對線程請求。代碼清單中使用while循環輪詢線程。
public IActionResult Sync()
{
short num = 10;
var thread = new Thread(new ParameterizedThreadStart(this.Add));
thread.Start(num);
while (thread.IsAlive) ;
return Json(DateTime.Now + "result:" + result);
}
void Add(object num)
{
Thread.Sleep(2000);
this.result =(short)num ;
Console.WriteLine(DateTime.Now);
}
1.4. 異步I/O
真正的異步IO需要操作系統更強的支持。在異步IO模型中,當用戶線程收到通知時,數據已經被內核讀取完畢,並放在了用戶線程指定的緩沖區內,內核在IO完成后通知用戶線程直接使用即可。
public IActionResult Async()
{
var start = DateTime.Now;
short num = 10;
var result = Add(num).Result;
return Json("start:"+ start +" end: " + DateTime.Now + " ||| result: " + result);
}
async Task<short> Add(short num)
{
await Task.Delay(2000);
return ++num;
}
關於異步的更詳細的使用可參看 http://www.cnblogs.com/vipyoumay/p/5663950.html
1.5. 總結
1.同步與異步關注的是消息通信機制 (synchronous communication/ asynchronous communication)
所謂同步,就是在發出一個 調用
時,在沒有得到結果之前,該調用
就不返回。但是一旦調用返回,就得到返回值了。換句話說,就是由調用者
主動等待這個調用
的結果。而異步則是相反,調用
在發出之后,這個調用就直接返回了,所以沒有返回結果。換句話說,當一個異步過程調用發出后,調用者不會立刻得到結果。而是在調用
發出后,被調用者
通過狀態、通知來通知調用者,或通過回調函數處理這個調用。
你打電話問書店老板有沒有《分布式系統》這本書,如果是同步通信機制,書店老板會說,你稍等,”我查一下",然后開始查啊查,等查好了(可能是5秒,也可能是一天)告訴你結果(返回結果)。而異步通信機制,書店老板直接告訴你我查一下啊,查好了打電話給你,然后直接掛電話了(不返回結果)。然后查好了,他會主動打電話給你。在這里老板通過“回電”這種方式來回調。
2. 阻塞與非阻塞關注的是程序在等待調用結果(消息,返回值)時的狀態.
阻塞調用是指調用結果返回之前,當前線程會被掛起。調用線程只有在得到結果之后才會返回。非阻塞調用指在不能立刻得到結果之前,該調用不會阻塞當前線程。
你打電話問書店老板有沒有《分布式系統》這本書,你如果是阻塞式調用,你會一直把自己“掛起”,直到得到這本書有沒有的結果,如果是非阻塞式調用,你不管老板有沒有告訴你,你自己先一邊去玩了, 當然你也要偶爾過幾分鍾check一下老板有沒有返回結果。在這里阻塞與非阻塞與是否同步異步無關。跟老板通過什么方式回答你結果無關
【1】http://www.jianshu.com/p/77332a3b07b5
【2】http://kb.cnblogs.com/page/85931
【3】https://www.zhihu.com/question/19732473