【问题标题】:Is my method really async?我的方法真的是异步的吗?
【发布时间】:2014-04-17 21:34:52
【问题描述】:

我有这样的方法:

public async Task<IEnumerable<Model>> Get([FromUri]IList<string> links)
{
    IList<Model> list = new List<Model>();
    foreach (var link in links)
    {
        MyRequestAsync request = new MyRequestAsync(link);
        list.Add(await request.GetResult());
    }

    return list;
}

但我只是想知道它是否真的是async,因为我认为list.Add(await request.GetResult());return list; 打破了async 方法的性质。

如果我错了,请纠正我,如果我是对的,我该如何解决?

更新:据我了解,我必须这样做 C# 5.0 async await return a list return await Task.Run(() =&gt; new List&lt;string&gt;() {"a", "b"}); 但不确定如何将其应用于我的情况。

【问题讨论】:

  • 我想你可能不明白异步 的真正含义。我通常建议人们从 Eric Lippert 的 blog post 开始阅读以了解 asyncawait 关键字。

标签: c# asynchronous c#-5.0 async-await


【解决方案1】:

您的方法是异步的,但可能没有充分利用资源。

您的方法将做的是进入foreach 循环,创建MyRequestAsync 对象,然后(在await 点)它将放弃其线程,直到结果可用。一旦结果可用,将找到一个合适的线程并且该方法将恢复运行。它将结果添加到list 并返回到循环的顶部,并一遍又一遍地重复整个过程。

但是,请考虑这一点 - 如果这些请求是独立的,您可以改为并行发出每个请求,然后仅在 所有 请求完成后继续运行您的方法。就像这样:

public async Task<IEnumerable<Model>> Get([FromUri]IList<string> links)
{
    IList<Task<Model>> list = new List<Task<Model>>();
    foreach (var link in links)
    {
        MyRequestAsync request = new MyRequestAsync(link);
        list.Add(request.GetResult());
    }

    return new List<Model>(await Task.WhenAll(list));
    //Or just
    //return await Task.WhenAll(list);
    //Since we don't need to return a list
}

而且,对于愚蠢的观点,您可以将整个方法重写为:

return await Task.WhenAll(from l in links select new RequestAsync(l).GetResult());

但这可能会降低它的可读性。

【讨论】:

  • 您无需创建List&lt;Model&gt; 即可在您的第一个代码示例中从Task.WhenAll 返回IEnumerable&lt;Model&gt;,就像您在第二个代码示例中所做的那样。
  • @PauloMorgado - 这就是它在返回下方的注释代码中所说的。
  • Parallel.Foreach 在这里不合适有什么原因吗?
【解决方案2】:

在我看来,I/O 是async,因此该方法可以称为“真正异步”。
async 意味着 I/O 在等待某事时不会阻塞线程(这里结果),但不是在“做某事”时(此处为 list.Add)。

【讨论】:

    【解决方案3】:

    这有点不可能,因为你调用的任何东西都可能是阻塞操作。如果某处隐藏了阻塞操作,则此方法也会阻塞。如果你想让一个方法成为非阻塞的和/或只使用可扩展的异步 IO,你必须检查你所做的和你调用的所有事情。

    也就是说你的代码看起来像是非阻塞的,因为它使用了await(而不是Task.Wait)。稍微简化一下,此方法将在第一个 await 操作上返回,这可能正是您所需要的。

    【讨论】:

    • 代码刚刚在debug 上工作,但是当not on debug 我没有得到任何结果(我想我遇到了死锁)因为我的理解return list; 没有等到list.Add(await request.GetResult()); 完成
    • 它确实在等待。这就是await 的意义所在。它暂停该方法,直到给定任务完成。使用调试器在运行时检查列表。找出未正确填写的原因。
    • 调试时未出现任何错误。在这里问了相关问题stackoverflow.com/questions/23134243/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-25
    • 2014-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-30
    相关资源
    最近更新 更多