异步编程异常和死锁处理
2015-08-07 12:43
267 查看
在.NET异步编程中,通常使用async和await这对黄金搭档,返回类型使用Task或Task<T>。在方法前面加async表示这个方法运行异步,在方法内使用await表示执行一个异步等待。
下面是一个简单例子:
当执行DoSth方法,第一个await执行一个异步等待,当执行完成,就继续执行下面的代码。在async修饰的方法内部,一个await就是一个异步等待,可以包含多个await, 每一个await执行完毕才会执行它后面的代码,也就是说在DoSth内部是同步的。
各个await在哪个线程中运行呢?
默认情况下是在当前线程中运行,不过.NET提供了ConfigureAwait方法,用来设置await在哪个线程中运行。
以上,当第一个await运行在控制台项目所在的线程中,第二个await将在线程池上运行。
我们无法保证每个await不会抛出异常,通常按如下的方式捕获异常。
由于抛出的异常会放在Task对象中,所以也可以这么写:
异步编程也会出现死锁。
以上,如果调用FirstThing方法就会出现死锁的情况。
→执行FirstThing方法
→在FirstThing方法内部执行DoSthSync方法,这时,当前上下文线程被阻塞
→来到DoSthSync方法中,其中的await试图捕获当前上下文线程,而当前的上下线程已经被阻塞在那里了,造成死锁。
死锁如何解决死锁呢?
可以在DoSthSync内部不使用当前上下文线程,改用线程池中的线程,修改如下:
或者,让FirstThing变成一个异步方法。修改如下:
下面是一个简单例子:
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();
}
相关文章推荐
- Matlab--数学建模
- C++实现的Vector类
- windows下python文件与文件夹操作
- Java窗体加载时组件不显示的解决方法
- 理解Quartz原理
- Java核心技术第9版中文扫描版
- Java 使用线程池递归压缩一个文件夹下的所有子文件
- 零基础学python-模块的导入与重载
- 零基础学python-模块的导入与重载
- JavaSE----面向对象(多态、抽象类、接口)
- org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider
- 【开发环境】JAVA 环境变量批处理
- PHPCMS 利用联动菜单实现分类筛选功能
- 使用newLISP由SMTPserver发送电子邮件
- CRC校验代码整理
- python菜鸟日记6
- python基础学习笔记<Web开发>
- C语言位运算 简解
- php AES加密兼容.net
- [LeetCode] Validate Binary Search Tree