假设我只想在async
中运行一个方法。
所以我有一个async
方法,如下所示:
public async Task Load(){
Task task1 = GetAsync(1);
Task task2 = GetAsync(2);
Task task3 = GetAsync(3);
var data1 = await task1; // <--Freezes here when called from GetSomethingElse()
var data2 = await task2;
var data3 = await task3;
..process data..
}
然后,我尝试将另一个方法中的async
方法作为一个任务调用,并希望它等待直到完成特定的async
代码。问题是它不是。当它到达Load()
中的第一个Load()
时,它只是没有完成加载。调试器变为空白,不会出现其他错误。
async
方法可以从非async
方法调用吗?我之所以不需要这个特定的任务是async
,而是因为我需要Load()
函数。
public void GetSomethingElse(){
var task1 = Load().Wait();
}
这怎麽可能?
我甚至尝试过将Load()
方法更改为使用var data = task1.Wait()
等,而不是await
,不管我尝试了哪种方式,仍然没有区别。如果有人能帮忙的话,我们将不胜感激。
发布于 2014-12-14 22:20:10
你的手上可能有个僵局。在一个需要完成该线程的任务上,使用Wait()
阻止一个线程,因为ASP.Net (也是在GUI环境中)使用了一个SynchronizationContext
。
您应该使用ConfigureAwait(false)
告诉侍者不要捕获上下文。在第一个await
上这样做就足够了,因为其余的SynchronizationContext
都没有可以捕获的:
public async Task Load()
{
Task task1 = GetAsync(1);
Task task2 = GetAsync(2);
Task task3 = GetAsync(3);
var data1 = await task1.ConfigureAwait(false);
var data2 = await task2;
var data3 = await task3;
//..process data.
}
但是,建议始终使用ConfigureAwait
,除非希望捕获SynchronizationContext
,因此更好的标准是:
public async Task Load()
{
Task task1 = GetAsync(1);
Task task2 = GetAsync(2);
Task task3 = GetAsync(3);
var data1 = await task1.ConfigureAwait(false);
var data2 = await task2.ConfigureAwait(false);
var data3 = await task3.ConfigureAwait(false);
//..process data.
}
在您的例子中,如果您想在all之后继续完成任务,那么您应该使用Task.WhenAll
而不是对每个任务分别使用await
:
public async Task Load()
{
await Task.WhenAll(GetAsync(1), GetAsync(2), GetAsync(3)).ConfigureAwait(false);
// process data.
}
注意:通常不鼓励在异步上进行同步,因为它没有好处(您在整个操作过程中阻塞了一个线程),并且可能导致死锁(比如这个)。
发布于 2014-12-14 23:00:50
我觉得你有一个典型的僵局场景。有关更多详细信息,请参阅这个职位。当您有一个await
语句时,当前的SynchronizationContext
存储在await
调用之前,然后恢复,然后将方法的其余部分提交给它。在GUI应用程序中,只有一个与该上下文相关联的线程,因此方法的其余部分被调度在GUI线程上执行,但它不能执行,因为Wait()
是阻塞该GUI线程的阻塞调用。
试一试:
public async Task Load(){
Task task1 = GetAsync(1).ConfigureAwait(false);
Task task2 = GetAsync(2).ConfigureAwait(false);
Task task3 = GetAsync(3).ConfigureAwait(false);
var data1 = await task1; // <--Freezes here when called from GetSomethingElse()
var data2 = await task2;
var data3 = await task3;
..process data..
}
如果GetAsync
内部有任何等待,您可能还必须在那里添加.ConfigureAwait(false)
。
发布于 2014-12-14 22:26:04
您将按以下方式更改Load函数:
public async Task Load(){
await new TaskFactory().StartNew(() =>
{
Task task1 = GetAsync(1);
Task task2 = GetAsync(2);
Task task3 = GetAsync(3);
var data1 = await task1; // <--Freezes here when called from GetSomethingElse()
var data2 = await task2;
var data3 = await task3;
..process data..
});
}
https://stackoverflow.com/questions/27478178
复制相似问题