2015-05-19 122 views
0

所以..這可能是一個愚蠢的問題。使用EF6異步會提高性能VS在一個任務包同步EF6電話(假定數據庫調用是一個Web API REST API方法內)異步EF 6 vs包裝同步EF

即我不能讓我的頭完全圍繞WHY,爲什麼是這樣的:

//wrapping synch with asynch 
return await Task.Run(() => 
{ 
    var albums = this.context.Albums 
       .Where(x => x.Artist.ID == artist.ID) 
       .ToList(); 
    return albums; 
}); 

比這更糟糕:

//using async 
return await this.context.Albums 
      .Where(x => x.Artist.ID == artist.ID) 
      .ToListAsync(); 

注:我閱讀這篇文章http://blogs.msdn.com/b/pfxteam/archive/2012/03/24/10287244.aspx這似乎是說(簡單化)「不要只W¯¯說唱同步方法,更有效地重寫方法「。

問題1,那是EF6的異步實現做了什麼?我假設它在實現中使用異步I/O?

問題2(和我真正的問題) - 可以有人解釋爲什麼這樣比較好?在數據庫操作完成之前,兩種實現都不會導致釋放請求線程來處理其他請求嗎?

回答

5

比方說,你正在烘烤一個大的節日晚餐。將會有大量的食物,包括一個大雞的主菜。烹飪需要很長時間,所以你先準備好,然後把它放入烤箱中,然後設定一個計時器以便稍後再檢查它,然後繼續準備下一道菜(土豆泥)。

你不能坐在那裏等待(同步)那隻雞完成;你需要讓它做飯(異步),而你去準備所有其他的菜餚。如果您在開始其他任何事情之前等待雞完成,除了您超級無聊之外,當您完成其他所有事情時,雞肉會變得冰冷。

現在有幾種方法可以使您在做其他工作時進行此操作(讓雞肉做飯)。例如,您可以設置一個計時器並在計時器通知您時間到了之後立即檢查計時器。另一個解決方案是不能自己工作。你可以去抓你的兒子,讓他坐在爐子前面等待雞準備好,讓他在準備好時通知你。

使用計時器類似於單線程異步解決方案。 (每個人都是一個線程)。只有一個工作者(你),並且你開始異步工作,在需要做事情時有異步通知,但是一次只處理一件事情。廚房中有多個人類似於多線程應用程序。如果你使用這些多人來真正完成多項任務,而這些任務需要一個真正的人同時工作(比如說,當你的兒子在洗蘆筍時你正在搗爛土豆),那麼你就完成了你的工作更快。當你使用那個額外的人(線程)不做任何事情,而是坐在那裏等待某件事完成時,當你離開工作時,那麼你只是在浪費那個人的(線程)時間。他們寧願離開,做一些有成效的事情。

因此,要完全剝離類比,當您使用Task.Run同步執行IO時,您正在線程池中調度工作,分配的線程只需要坐在那裏無所事事(而不是做實際的工作)等待IO完成。當你只使用固有的異步IO操作時,根本沒有其他線程參與

+0

非常好的比喻。 – juharr

+0

感謝您的回答和類比。說得通。但是,EF6異步方法(ToListAsync)*固有地*異步?是否因爲他們在實現中使用異步I/O? – HokieMike

+0

@HokieMike是的。就其本質而言,IO幾乎總是異步的。幾乎任何時候你看到同步IO方法都意味着,某個地方出於某種原因*會異步阻塞,直到異步通知表明它可以繼續。許多IO操作的API都不願意隱藏固有的異步;但現在它在C#中變得越來越常見,以便將異步地顯示給調用者。 – Servy