程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 異步編程異常和死鎖處理,異步編程

異步編程異常和死鎖處理,異步編程

編輯:C#入門知識

異步編程異常和死鎖處理,異步編程


 

在.NET異步編程中,通常使用async和await這對黃金搭檔,返回類型使用Task或Task<T>。在方法前面加async表示這個方法運行異步,在方法內使用await表示執行一個異步等待。

 

下面是一個簡單例子:

 

        static void Main(string[] args)
        {
            Doth();
            Console.ReadKey();
        }
        static async Task Doth()
        {
            int i = 2;
            await Task.Delay(TimeSpan.FromSeconds(2));
            i += 2;
            await Task.Delay(TimeSpan.FromSeconds(2));
            Console.WriteLine(i);
        }

 

當執行DoSth方法,第一個await執行一個異步等待,當執行完成,就繼續執行下面的代碼。在async修飾的方法內部,一個await就是一個異步等待,可以包含多個await, 每一個await執行完畢才會執行它後面的代碼,也就是說在DoSth內部是同步的。

 

各個await在哪個線程中運行呢?

 

默認情況下是在當前線程中運行,不過.NET提供了ConfigureAwait方法,用來設置await在哪個線程中運行。

 

        static async Task Doth()
        {
            int i = 2;
            await Task.Delay(TimeSpan.FromSeconds(2)).ConfigureAwait(false);
            i += 2;
            await Task.Delay(TimeSpan.FromSeconds(2)).ConfigureAwait(false);
            Console.WriteLine(i);
        }

 

以上,當第一個await運行在控制台項目所在的線程中,第二個await將在線程池上運行。

 

我們無法保證每個await不會拋出異常,通常按如下的方式捕獲異常。

 

async Task DosthAsync()
{
    try
    {
        await PossibleExceptionAsync();
    }
    catch(NotSuppotedException ex)
    {
        LogException(ex);
        throw;
    }
}

 

由於拋出的異常會放在Task對象中,所以也可以這麼寫:

 

async Task DosthAsync()
{
    Task task = PossibleExceptionAsync();
    try
    {
        await task;
    }
    cach(NotSupportedException ex)
    {
        LogException(ex);
        throw;
    }
}

 

異步編程也會出現死鎖。

 

async Task DoSthSync()
{
    await Task.Delay(TimeSpan.FromSeconds(1));
}
void FirstThing()
{
    Task tak = DoSthSync();
    task.Wait();
}

 

以上,如果調用FirstThing方法就會出現死鎖的情況。

 

→執行FirstThing方法
→在FirstThing方法內部執行DoSthSync方法,這時,當前上下文線程被阻塞
→來到DoSthSync方法中,其中的await試圖捕獲當前上下文線程,而當前的上下線程已經被阻塞在那裡了,造成死鎖。

 

死鎖如何解決死鎖呢?

 

可以在DoSthSync內部不使用當前上下文線程,改用線程池中的線程,修改如下:

 

async Task DoSthSync()
{
    await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
}

 

或者,讓FirstThing變成一個異步方法。修改如下:

 

async Task DoSthSync()
{
    await Task.Delay(TimeSpan.FromSeconds(1));
}
async Task FirstThing()
{
    await DoSthSync();
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved