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, ...
随机推荐
- C# .net MD5加密函数
using System.Web.Security; string password =FormsAuthentication.HashPasswordForStoringInConfigFile(t ...
- Swift4 - 动态计算UITableView中tableHeaderView的高度 - 获取子控件高度和宽度
核心 : /// 获取 子控件高度 func sizeHeaderToFit(view:UIView) { view.setNeedsLayout() view.layoutIfNeeded() le ...
- ADF学习实用网站
ADF中所有组件工功能例子 http://jdevadf.oracle.com/adf-richclient-demo/faces/components/dialog.jspx;jsessionid= ...
- PAT 1003 我要通过!(20)(代码+思路)
1003 我要通过!(20)(20 分)提问 "答案正确"是自动判题系统给出的最令人欢喜的回复.本题属于PAT的"答案正确"大派送 -- 只要读入的字符串满足下 ...
- Java NIO系列教程(四) Scatter 和 Gather
Java NIO系列教程(四) Scatter 和 Gather Java NIO 开始支持 scatter/gather,scatter/gather 用于描述从 Channel(译者注:Chann ...
- jetty无法即时更新html、js、css等静态文件的解决办法
网上搜了一大堆方法.最常见的是找到jetty\etc\webdefault.xml文件,找到useFileMappedBuffer参数,把true改为false <init-param> ...
- MySQL之练习题5
.将所有的课程的名称以及对应的任课老师姓名打印出来,如下: SELECT cname,tname FROM course INNER JOIN teacher WHERE course.teacher ...
- 解决Docker时区与主机时区不一致的问题
在Dockerfile里面增加以下红色的部分 FROM hub.chinacloud.com/common/jdk:8MAINTAINER xxx@chinacloud.com.cn RUN mkdi ...
- js正则表达式汇集
1.只允许中文.字母.数字.中划线.下划线.空格.中文的().英文的()和#,只能以数字.中文.字母.下划线开头,长度为2至40之间 validateTemplateName: function(va ...
- UVa 11367 Full Tank? (DP + Dijkstra)
题意:n个城市有m条道路.每个城市的油价不一样,给出起点s和终点t,以及汽车的油箱的容量,求从城市s到城市 t 的最便宜路径. 析:dp[u][i] 表示在第 u 个城市,还剩下 i L升油,一开始用 ...