首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >在非异步方法中使用异步

在非异步方法中使用异步
EN

Stack Overflow用户
提问于 2014-12-14 21:56:14
回答 3查看 2.5K关注 0票数 14

假设我只想在async中运行一个方法。

所以我有一个async方法,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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()函数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void GetSomethingElse(){
    var task1 = Load().Wait();      
}

这怎麽可能?

我甚至尝试过将Load()方法更改为使用var data = task1.Wait()等,而不是await,不管我尝试了哪种方式,仍然没有区别。如果有人能帮忙的话,我们将不胜感激。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-12-14 22:20:10

你的手上可能有个僵局。在一个需要完成该线程的任务上,使用Wait()阻止一个线程,因为ASP.Net (也是在GUI环境中)使用了一个SynchronizationContext

您应该使用ConfigureAwait(false)告诉侍者不要捕获上下文。在第一个await上这样做就足够了,因为其余的SynchronizationContext都没有可以捕获的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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,因此更好的标准是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public async Task Load()
{
    await Task.WhenAll(GetAsync(1), GetAsync(2), GetAsync(3)).ConfigureAwait(false);
    // process data.
}

注意:通常不鼓励在异步上进行同步,因为它没有好处(您在整个操作过程中阻塞了一个线程),并且可能导致死锁(比如这个)。

票数 11
EN

Stack Overflow用户

发布于 2014-12-14 23:00:50

我觉得你有一个典型的僵局场景。有关更多详细信息,请参阅这个职位。当您有一个await语句时,当前的SynchronizationContext存储在await调用之前,然后恢复,然后将方法的其余部分提交给它。在GUI应用程序中,只有一个与该上下文相关联的线程,因此方法的其余部分被调度在GUI线程上执行,但它不能执行,因为Wait()是阻塞该GUI线程的阻塞调用。

试一试:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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)

票数 2
EN

Stack Overflow用户

发布于 2014-12-14 22:26:04

您将按以下方式更改Load函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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..
    });
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27478178

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文