Ren*_*Ren 2 .net c# multithreading async-await
我正在尝试使用概念验证应用程序,我想知道下面两个异步方法的内部结构.
会Task.Result
导致任何问题DoSomethingAsync1()
吗?
我已经阅读了一些Task.Result
可能导致的阻塞和死锁问题,但我认为在这种情况下不会,因为它运行在一个单独的任务上,并且有一个await
已经确保结果的任务.
这里的主要目标是在单独的任务上运行异步方法,因为此操作不依赖于主asp.net线程,更重要的是捕获由抛出的任何异常 DoSomethingThatTakesReallyLong()
另外,在ActionResult
DoSomething()
,我应该设置.ConfigureAwait(false);
?
在下面的场景中,我是否需要注意隐藏的瓶颈/问题?
更新
我已经解决了我在这里输入问题时所做的拼写错误.(返回用户对象而不是任务)
而且,async
在实际应用中,我无权将所有更高级别的方法转换为一次性.所以,这是我打算一步一步地做的事情,从不依赖于主线程的操作开始.
我非常感谢所有最佳实践答案,但这是一个小游乐场代码,我的主要问题是要知道是否存在内部差异DoSomethingAsync1()
,DoSomethingAsync2()
这可能会导致某些条件下的任何问题.
从阅读评论和答案,我得到一个想法,没有太大的区别.
private static async Task<User> DoSomethingAsync1()
{
try
{
var longRunningTask = Task<User>.Factory.StartNew(() => LongRunner.LongRunnerInstance.DoSomethingThatTakesReallyLong());
var user = await longRunningTask;
//Will the below line of code cause any issue?
Console.WriteLine(longRunningTask.Result.Id);
return user;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return null;
}
}
private static async Task<User> DoSomethingAsync2()
{
try
{
var longRunningTask = Task<User>.Factory.StartNew(() => LongRunner.LongRunnerInstance.DoSomethingThatTakesReallyLong());
var user = await longRunningTask;
Console.WriteLine(user.Id);
return user;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return null;
}
}
public ActionResult Index()
{
//Things that run on main Asp.NET thread
//Things that run independently
//Won't be using the task returned here at the moment.
DoSomethingAsync1();
//Do more things on main Asp.NET thread if needed
return View();
}
Run Code Online (Sandbox Code Playgroud)
https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
谢谢
Task.Result会导致任何问题[如果任务已经完成]吗?
Task<T>.Result
将同步等待任务完成(相同task.Wait()
),然后返回结果(与之相同await task
).
由于您的任务已经完成,因此只有一个区别Result
,await
这很重要:Result
将异常包装在一个AggregateException
.出于这个原因(并且还使代码更加重构安全),我使用await
而不是Result
尽可能.也就是说,采取这种DoSomethingAsync2
方法.
我已经阅读了一些关于Task.Result可能导致的阻塞和死锁问题,但我认为在这种情况下它不会,因为它运行在一个单独的任务上,并且已经确保结果的任务等待.
它不会因为它在线程池上下文中运行.
所以,这是我打算一步一步地做的事情,从不依赖于主线程的操作开始.
你可能会发现我的棕色异步文章很有帮助.在那篇文章中,我将这种技术称为"线程池黑客".
在下面的场景中,我是否需要注意隐藏的瓶颈/问题?
一些:
你不应该在ASP.NET上发射(即,在不消耗其任务的情况下调用异步方法).
您不应该公开伪异步方法(即具有异步签名但通过阻塞线程池线程实现的方法).而不是使用Task.Run
以实现一种方法,使用Task.Run
来调用一个方法.
结合这三个点,线程池哈克的正确结构是用Task.Run
与GetAwaiter().GetResult()
(这只是喜欢Result
,但避免了AggregateException
包装):
public ActionResult Index()
{
var r = Task.Run(() => LongRunner.LongRunnerInstance.DoSomethingThatTakesReallyLong())
.GetAwaiter().GetResult();
return View();
}
Run Code Online (Sandbox Code Playgroud)
作为最后一个问题,只要在ASP.NET应用程序中使用此模式,应用程序的可伸缩性就会降低.您的应用程序现在使用两个,而不是在使用一个线程DoSomethingThatTakesReallyLong
; 这也可能会抛弃ASP.NET线程池启发式.在过渡期间这可能是可以接受的async
,但要记住它作为完成过渡的动力.
归档时间: |
|
查看次数: |
881 次 |
最近记录: |