我用一个控制器和一个方法创建了一个简单的WebApi项目:
public static class DoIt
{
public static async Task<string> GetStrAsync(Uri uri)
{
using (var client = new HttpClient())
{
var str = await client.GetStringAsync(uri);
return str;
}
}
}
public class TaskRunResultController : ApiController
{
public string Get()
{
var task = Task.Run(() =>
DoIt.GetStrAsync(new Uri("http://google.com"))
);
var result = task.Result;
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
我非常了解async/await和tasks; 斯蒂芬克莱里几乎虔诚地跟随他.只是存在.Result让我焦虑,我希望这会陷入僵局.我知道这Task.Run(...)很浪费,导致在等待异步DoIt()完成时占用一个线程.
问题是这不是死锁,而是让我心悸.
我看到一些答案,如/sf/answers/2282496401/,我也观察到SynchronizationContext.Currentlambda执行时为null.但是,我也有类似的问题,问为什么上面的代码会出现死锁,而且我发现死锁ConfigureAwait(false)是在使用(不捕获上下文)的情况下发生的.Result.
是什么赋予了?
假设我们必须通过异步流向数据库写下1000个元素的列表.是等待1000次异步插入语句,还是将所有1000个插入包装在一个封装到Task.Run语句中的单个同步方法中等待一次?
例如,SqlCommand每个方法都加上他的async版本.在这种情况下,我们有一个insert语句,所以我们可以调用ExecuteNonQuery或ExecuteNonQueryAsync.
通常,在异步/等待指南上,我们读到如果您有某个方法可用的异步版本,则应该使用它.所以我们写一下:
async Task Save(IEnumerable<Savable> savables)
{
foreach(var savable in savables)
{
//create SqlCommand somehow
var sqlCmd = CreateSqlCommand(savable);
//use asynchronous version
await sqlCmd.ExecuteNonQueryAsync();
}
}
Run Code Online (Sandbox Code Playgroud)
这段代码很清楚.但是,每次从await部分出来时,它也会在UI线程上返回,然后在遇到的下一个await中返回后台线程,依此类推(不是吗?).这意味着用户可以看到一些延迟,因为UI线程不断地被继续await执行下一个foreach周期而中断,并且在那段时间内UI冻结了一点.
我想知道我是否更好地编写这样的代码:
async Task Save(IEnumerable<Savable> savables)
{
await Task.Run(() =>
{
foreach(var savable in savables)
{
//create SqlCommand somehow
var sqlCmd = CreateSqlCommand(savable);
//use synchronous version
sqlCmd.ExecuteNonQuery();
}
});
}
Run Code Online (Sandbox Code Playgroud)
以这种方式,整个foreach在辅助线程上执行,而在UI线程和辅助线程之间没有连续切换.这意味着UI线程可以在整个持续时间内foreach(例如微调器或进度条)自由更新View ,也就是说,用户不会感知到任何延迟.
我对吗?或者我错过了一些关于"异步一直向下"的事情?
我不是在寻找简单的基于意见的答案,我正在寻找async/await指南的解释,以及解决它的最佳方法.
编辑: …
这是我之前发布的一个问题的后续问题.使用Task.Run调用异步方法似乎错了?
我认为承包商编写的代码是错误的,但是从提供的答案开始,我现在想知道这是否是图书馆的错误.该库公开了我需要使用的两种方法.一个返回一个"模板",一个消耗该模板的一部分(无论如何它都在我的实现中).但两者都是async返回的方法Tasks.
解释我的库有方法:
public Task<TemplateInfo> TemplateInfo(TemplateInfoRequest request);
public Task<List<EmailResult>> SendMessageTemplate(SendMessageTemplateRequest request);
Run Code Online (Sandbox Code Playgroud)
我需要这样称呼它们:
public bool SendMessage()
{
var template = TemplateInfo(...);
var message = //use template to create message
var sendResponse = SendMessageTemplate(message);
return sendResponse.Count > 0;
}
Run Code Online (Sandbox Code Playgroud)
所以第二次通话依赖于第一次.这是异步对我没有意义的地方.我不能也不想并行运行这些.我想按顺序运行它们.我希望我的方法是同步的.
由于您在异步方法上阻塞(您不应该这样做),因此您可能会陷入僵局.
那么如何async以这样的方式访问这些方法,即依次处理它们并返回同步结果但不会导致死锁?