我的方法真的是异步的吗

本文关键字:异步 方法 真的 我的 | 更新日期: 2023-09-27 17:58:50

我有这样的方法:

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异步等待返回一个列表return await Task.Run(() => new List<string>() {"a", "b"});,但不确定如何将其应用于我的案例。

我的方法真的是异步的吗

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

您的方法将进入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());

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

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

这有点不可能判断,因为您调用的任何操作都可能是阻塞操作。如果某个地方隐藏了一个阻塞操作,这个方法也会阻塞。如果你想让一个方法不阻塞和/或只使用可伸缩的异步IO,你必须检查你所做的和调用的一切。

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