我的方法真的是异步的吗
本文关键字:异步 方法 真的 我的 | 更新日期: 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
操作时返回,这可能是我们所需要的。