异步编程异常和死锁处理

 

在.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();
 
 
}
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值