c# async await


1.async await

private void Form2_Load(object sender, EventArgs e)
        {
            Console.WriteLine("main:"+Thread.CurrentThread.ManagedThreadId);
            DoSth();  //不加await不等待DoSth執行完成直接先彈出form2_load
            MessageBox.Show("form2_load");
          
        }

        async Task DoSth()
        {
            Do1(); //不加await不等待Do1執行完畢(先彈出 DoSth executed after 3s 后彈出 do1 after 5s)相當於並發,加了await就會等待Do1執行完再執行后續相當於阻塞
            await Task.Delay(3000);   //這里不能用Thread.Sleep代替 原因見結尾處紅色處文字(如果不開線程則Thread.Sleep會阻塞住主線程 看不到先彈出 DoSth executed after 3s效果)
            Console.WriteLine("dosth:"+Thread.CurrentThread.ManagedThreadId);
            MessageBox.Show("DoSth executed after 3s");
        }

        async Task Do1()
        {
            await Task.Delay(5000);//這里不能用Thread.Sleep代替 原因見結尾處紅色處文字(如果不開線程則Thread.Sleep會阻塞住主線程 看不到先彈出 DoSth executed after 3s效果)
            Console.WriteLine("do1:"+Thread.CurrentThread.ManagedThreadId);
            MessageBox.Show("do1 after 5s");
        }

  

線程id輸出3個都一樣 原因(http://www.cnblogs.com/mushroom/p/4575417.html):

有言論說Async不用開線程,也有說需要開線程的,從單一方面來講都是對的,也都是錯的。 上面源碼是從簡分析的,具體async內部會涉及到線程上下文切換,線程復用、調度等。 想深入的同學可以研究下ExecutionContextSwitcher、 SecurityContext.RestoreCurrentWI、ExecutionContext這幾個東東。

其實具體的物理線程細節可以不用太關心,知道其【主線程A邏輯->異步任務線程B邏輯->主線程C邏輯】這個基本原理即可。 另外Async也會有線程開銷的,所以要合理分業務場景去使用。

 

From:http://www.cnblogs.com/xuejianxiyang/p/7089280.html

 

 

 

以下摘自知乎:

https://www.zhihu.com/question/30601778

最近在看《C#圖解教程》,其中第20章講解了.NET 4.5和C# 5.0新添加的異步編程模型async/await,舉了一個在GUI中執行異步操作的例子:

private async void btnDoStuff_Click(object sender, RoutedEventArgs e)
{
    btnDoStuff.IsEnabled = false;
    lblStatus.Content = "Doing Stuff";

    await Task.Delay(4000);

    lblStatus.Content = "Not Doing Anything";
    btnDoStuff.IsEnabled = true;
}


上面這個方法是一個按鈕空間Click事件的事件響應代碼。

我的問題是:按照我的理解,控件的響應代碼應該是在GUI線程里面被調用的,而且對於GUI應用程序來說,GUI線程一般只有一個,並且所有和GUI控件方面的交互都應該通過GUI線程來完成。那么用await修飾的異步方法是在哪個線程中被調用的?為什么上面這個事件處理方法不會阻塞GUI?
我還看到其它一些描述是說使用async/await異步模式不會生成新的線程,那么只在原來已有線程的基礎上面如何做到異步運行?
總之,如何正確理解.NET 4.5和C# 5.0中的async/await異步編程模式?

 

作者:Ivony
鏈接:https://www.zhihu.com/question/30601778/answer/48717630
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

await修飾的方法返回的是一個Task,而這個Task其實就是一個異步句柄,如果我來取名字的話多半就叫做IAsyncHandler。

一個IAsyncHandler你可以想象成是這么一個東西:
public interface IAsyncHandler
{
  Register( Action continuation );
}

這是偽代碼,事實上不存在這么個東西。


注冊一個回調方法在異步操作完成后繼續,所以事實上這段代碼的原理像是這樣的:
private async void btnDoStuff_Click(object sender, RoutedEventArgs e)
{
  btnDoStuff.IsEnabled = false;
  lblStatus.Content = "Doing Stuff";

  var handler = Task.Delay(4000) as IAsyncHandler
  handler.Register( () =>
  {
    lblStatus.Content = "Not Doing Anything";
    btnDoStuff.IsEnabled = true;
  } );
}

當然上面全是偽代碼,但是如果你能看懂這段代碼在干什么,那么async基本就可以懂了,剩下的只是一些實現細節上的問題。


通常情況下,Task.Delay會立即返回一個Task對象,這個Task對象會在指定時間之后被標記為Completed,而被標記Completed就會立即開一個線程來進行延續的操作。

但是這里有個問題就是你這個方法是寫在UI線程里面的,控件的事件會被UI線程觸發,而UI線程上有個SynchronizationContext對象,這個對象的存在就會使得系統在異步回調的時候去捕獲源線程。在原來的線程(UI線程)去執行延續的任務。

而我們知道WinForm里面有個方法叫做Control.Invoke,可以把一個方法封送到UI線程去執行,而上面的工作和這個方法底層的原理其實是一樣的,所以,其實這段代碼用傳統的思維來理解的話像是這樣:
private async void btnDoStuff_Click(object sender, RoutedEventArgs e)
{
  btnDoStuff.IsEnabled = false;
  lblStatus.Content = "Doing Stuff";

  Action continuation = () =>
  {
    lblStatus.Content = "Not Doing Anything";
    btnDoStuff.IsEnabled = true;
  };

  Thread.Start( () =>
  {
    Thread.Sleep( 4000 );
    Control.Invoke( continuation );
  } );
}

 

 

異步並非必然是多線程的,譬如 yield 。

我舉個例子,我顯示一串文字,等用戶按一下按鈕再顯示下一串,在第一次顯示文字跟用戶按下按鈕之間,可以做很多事情,這里就是異步的,但不是多線程的。

有沒有辦法把兩次顯示字符串的操作,寫在同一個函數里?可以,最簡單的方法就是用yield。按鈕按下去時候就調用IEnumerator.MoveNext()

await 本身也不會創造線程,導致出現線程的是后面的那個執行Task 的函數。Task 概念上也不是多線程的,它只是把任務放到了線程池,但是如果任務還沒執行,馬上需求結果,它就會在當前線程執行,而非在另一個線程來執行。
所以異步和多線程之間,概念是要分清楚的。

另外,在F#里面,會有更多的異步模型,只是C#里暫時只能使用Task這個自動擋,讓人模糊了概念,只差了一個轉身。

 

 

 https://bbs.csdn.net/topics/392194509
實際上
async Task abc()
就相當於
void abc(Action callback)

async Task<int> abc
就相當於
void abc(Action<int> callback)
,async/await 語法是讓你把異步回調代碼用順序代碼的風格來寫,但是它也制造了麻煩,使得不求甚解的人會越來越糊塗。

 

異步實現:

https://www.cnblogs.com/renjing/p/Invoke.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM