c# async Task await Result 死锁
最近项目数据量较大,使用 async Task异步增加执行效率
遇到问题,当前有2个计算非常耗时,现在需要你优化一下,这2个计算并行执行,2个计算执行完成后将2个结果sum返回给用户
当前我是这样实现的
public async Task<ActionResult> Index()
{
System.Diagnostics.Debug.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}begin"); try
{
var t1Rlt = Test1();
var t2Rlt = Test2();
var a = t1Rlt.Result;
var b = t2Rlt.Result;
System.Diagnostics.Debug.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}结果【{a + b}】");
System.Diagnostics.Debug.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}end");
}
catch (Exception ex)
{ throw;
}
return View();
} public async Task<int> Test1()
{
return await Task.Run(() =>
{
for (int i = ; i < ; i++)
{
Thread.Sleep();
System.Diagnostics.Debug.WriteLine($"子①====线程{Thread.CurrentThread.ManagedThreadId}打印{i}");
}
return ;
});
} public async Task<int> Test2()
{
return await Task.Run(() =>
{ for (int i = ; i < ; i++)
{
Thread.Sleep();
System.Diagnostics.Debug.WriteLine($"子②====线程{Thread.CurrentThread.ManagedThreadId}打印{i}");
}
return ;
});
}
Index执行时大家觉得怎么样 返回300 是吧,我也这样以为了,但是实践是检验结果的唯一方式,程序执行后出错
“计算函数 result.get 超时 需要以不安全的方式中止”
呃。。。之前我确实是用例很多 async task 了 上面代码也没错 先并行执行,然后再去结果计算,但这样是不行的 因为
微软考虑到线程间切换如何保证程序的执行顺序不错乱
大家可以参考下这篇文章 https://www.cnblogs.com/OpenCoder/p/4434574.html 上面内容的大致意思就是说在使用await and async模式时,await关键字这一行后面的代码块会被一个context(也就是上面提到的ASP.NET request contex和UI context)线程继续执行,
如果我们将本例中调用top-level method的线程称为线程A(即context线程),由于GetJsonAsync方法也是由线程A调用的,所以当GetJsonAsync方法中await的GetStringAsync方法执行完毕后,
GetJsonAsync需要重新使用线程A执行await代码行之后的代码,而现在由于线程A在top-level method的代码中因为访问了jsonTask.Result被阻塞了
(因为线程A调用top-level method代码中jsonTask.Result的时候,await的GetStringAsync的Task还没执行完毕,所以被线程A阻塞),
所以GetJsonAsync无法重新使用线程A执行await代码行之后的代码块,也被阻塞,所以形成了死锁。也就是说top-level method代码中线程A因为
等待GetJsonAsync中await的GetStringAsync结束被阻塞,而GetStringAsync也等待线程A在top-level method的阻塞结束获得线程A来执行GetJsonAsync中await代码行后面的代码也被阻塞,
两个阻塞相互等待,相互死锁。 现在抛出正确写法供各位小伙伴参考
public async Task<ActionResult> Index()
{
System.Diagnostics.Debug.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}begin"); try
{
var t1Rlt = Test1();
var t2Rlt = Test2();
var a = await t1Rlt;
var b = await t2Rlt;
System.Diagnostics.Debug.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}结果【{a + b}】");
System.Diagnostics.Debug.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}end");
}
catch (Exception ex)
{ throw;
}
return View();
} public async Task<int> Test1()
{
return await Task.Run(() =>
{
for (int i = ; i < ; i++)
{
Thread.Sleep();
System.Diagnostics.Debug.WriteLine($"子①====线程{Thread.CurrentThread.ManagedThreadId}打印{i}");
}
return ;
});
} public async Task<int> Test2()
{
return await Task.Run(() =>
{ for (int i = ; i < ; i++)
{
Thread.Sleep();
System.Diagnostics.Debug.WriteLine($"子②====线程{Thread.CurrentThread.ManagedThreadId}打印{i}");
}
return ;
});
}
执行效果
截图执行结果是想告诉大家 await 执行结束后 主线程由那个线程接管 是随机的 不知道的小伙伴记住吧
c# async Task await Result 死锁的更多相关文章
- async/task/await
async/task/await三组合是.NET Framework 4.5带给.NET开发者的大礼,合理地使用它,可以提高应用程序的吞吐能力. 但是它的使用有点绕人,如果不正确使用,会带来意想不到的 ...
- 小心C# 5.0 中的await and async模式造成的死锁
平时在使用C# 5.0中的await and async关键字的时候总是没注意,直到今天在调试一个ASP.NET项目时,发现在调用一个声明为async的方法后,程序老是莫名其妙的被卡住,就算声明为as ...
- async、await在ASP.NET[ MVC]中之线程死锁的故事
场景重构 public ActionResult Index(string ucode) { string userInfo = GetUserInfo(ucode).Result; ViewData ...
- [转]小心C# 5.0 中的await and async模式造成的死锁
原文链接 https://www.cnblogs.com/OpenCoder/p/4434574.html 内容 UI Example Consider the example below. A bu ...
- wait 和async,await一起使用引发的死锁问题
在某个项目开发过程中,偶然间发现在UI线程中async,await,wait三者一起使用会引发一个必然性的死锁问题. 一个简单的实例,代码很简单,在界面上放置一个Button,并在Button的cli ...
- 异步方法的意义何在,Async和await以及Task的爱恨情仇,还有多线程那一家子。
前两天刚感受了下泛型接口的in和out,昨天就开始感受神奇的异步方法Async/await,当然顺路也看了眼多线程那几个.其实多线程异步相关的类单个用法和理解都不算困难,但是异步方法Async/awa ...
- Await Async Task
class Program { static void Main(string[] args) { Console.WriteLine("=======Start Main!======== ...
- The Task: Events, Asynchronous Calls, Async and Await
The Task: Events, Asynchronous Calls, Async and Await Almost any software application today will lik ...
- C# Task中的Func, Action, Async与Await的使用
在说Asnc和Await之前,先说明一下Func和Action委托, Task任务的基础的用法 1. Func Func是一种委托,这是在3.5里面新增的,2.0里面我们使用委托是用Delegate, ...
随机推荐
- 合并区间 · Merge Intervals & 插入区间 · Insert Interval
[抄题]: 给出若干闭合区间,合并所有重叠的部分. 给出的区间列表 => 合并后的区间列表: [ [ [1, 3], [1, 6], [2, 6], => [8, 10], [8, 10] ...
- 7-将本地的javaweb项目部署到Linux服务器的一般操作
一.基本流程介绍: 1.安装tomcat;2.安装mysql;3.将本地的javaweb导出成.war文件,传到服务器的tomcat/webapps/下面4.将数据库文件导出成.sql文件,传到服务器 ...
- mysql中GROUP_CONCAT的使用
现在有三个表,结构如下: cate表 CREATE TABLE `cate` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', ...
- Raft 一致性算法论文译文
本篇博客为著名的 RAFT 一致性算法论文的中文翻译,论文名为<In search of an Understandable Consensus Algorithm (Extended Vers ...
- Spring框架的事务管理之编程式的事务管理(了解)
1. 说明:Spring为了简化事务管理的代码:提供了模板类 TransactionTemplate,所以手动编程的方式来管理事务,只需要使用该模板类即可!!2.手动编程方式的具体步骤如下: 1.步骤 ...
- tp5链接访问
方法名:admin/DayActive/statistic 访问:admin/day_active/statistic
- boost::asio 学习草稿
http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio/ 可以多个线程拥有io_ ...
- 使用RSA进行信息加密解密的WebService示例
使用RSA进行信息加密解密的WebService示例 按:以下文字涉及RSA对WebService传递的数据的加密解密,如果您已经熟知RSA或是有其它更好的方法请不要往下看以免浪费时间. WebSer ...
- android 蓝牙通讯编程 备忘
1.启动App后: 判断->蓝牙是否打开(所有功能必须在打牙打开的情况下才能用) 已打开: 启动代码中的蓝牙通讯Service 未打开: 发布 打开蓝牙意图(系统),根据Activity返回进场 ...
- Deployment is out of date due to changes in the underlying project contents. Deployment is out of date due to changes in the underlying project contents. You'll need to manually 'Redeploy' the projec
原因1:导入的jar包路径不对,造成第一个错误, 原因2:设置右键工程->属性->myeclipse->web->deployment选use workbenk defaul ...

