C# 用异步方法选择
我发现了一个对我来说非常有用的方法,但我仍然不知道LINQ world中的等效方法还有哪些进一步的构造:C# 用异步方法选择,c#,linq,async-await,C#,Linq,Async Await,我发现了一个对我来说非常有用的方法,但我仍然不知道LINQ world中的等效方法还有哪些进一步的构造: public async Task<List<ObjectInfo>> GetObjectsInfo(string[] objectIds) { var result = new List<ObjectInfo>(objectIds.Length); foreach (var id in objectIds) { r
public async Task<List<ObjectInfo>> GetObjectsInfo(string[] objectIds)
{
var result = new List<ObjectInfo>(objectIds.Length);
foreach (var id in objectIds)
{
result.Add(await GetObjectInfo(id));
}
return result;
}
这些任务不是同时开始的吗?
在我的情况下,最好将它们串联运行
编辑1:回答西奥多·祖利亚斯的评论
当然,我忘记了方法名称中的异步后缀
GetObjectInfo异步方法向外部服务发出http请求。此外,该服务对请求的频率有限制,所以我使用以下结构
using (var throttler = new Throttler(clientId))
{
while (!throttler.IsCallAllowed(out var waitTime))
{
await Task.Delay(waitTime);
}
var response = await client.PerformHttpRequestAsync(request);
return response.Content.FromJson<TResponse>(serializerSettings);
}
Throttler知道每个客户端的最后一个请求的时间。在使用Whalll时,应考虑以下因素 如果任何提供的任务在故障状态下完成,则返回的任务也将在故障状态下完成,其中其异常将包含来自每个提供的任务的未包装异常集合 如果提供的任务都没有出现故障,但其中至少有一个已取消,则返回的任务将以取消状态结束 如果没有任何任务出现故障,也没有任何任务被取消,则生成的任务将以RANTO完成状态结束 如果提供的数组/枚举表不包含任务,则返回的任务在返回给调用方之前将立即转换为RanToCompletion状态 这意味着,虽然项目可能会同时运行,但您无法知道如何运行,因为这取决于机器的资源,并且您无法知道顺序,上述情况无法避免
如果您希望对每个案例和特定顺序进行特定的错误处理,那么第一个解决方案就是要走的路。它有点超越了async/await的要点,但不是全部。即使按顺序执行异步项,线程至少不会进入睡眠状态,并且在等待项准备就绪之前仍可使用。在使用whalll时,您应该考虑以下注意事项 如果任何提供的任务在故障状态下完成,则返回的任务也将在故障状态下完成,其中其异常将包含来自每个提供的任务的未包装异常集合 如果提供的任务都没有出现故障,但其中至少有一个已取消,则返回的任务将以取消状态结束 如果没有任何任务出现故障,也没有任何任务被取消,则生成的任务将以RANTO完成状态结束 如果提供的数组/枚举表不包含任务,则返回的任务在返回给调用方之前将立即转换为RanToCompletion状态 这意味着,虽然项目可能会同时运行,但您无法知道如何运行,因为这取决于机器的资源,并且您无法知道顺序,上述情况无法避免
如果您希望对每个案例和特定顺序进行特定的错误处理,那么第一个解决方案就是要走的路。它有点超越了async/await的要点,但不是全部。即使按顺序执行异步项,您的线程至少不会进入睡眠状态,并且在等待项准备就绪之前仍可使用。可能的重复:我们只知道将同步创建一组任务。我们可以假设它们将在热状态下创建,换句话说,它们已经开始创建,并且它们的创建速度足够快,可以认为是同步的。但我们需要查看GetObjectInfo的代码才能确定。哪一个BTW应该命名为GetObjectInfo async。因此任务是热的,因为它们是由异步方法创建的。每个任务的创建都涉及到节流器对象的创建,并调用其IsCallAllowed方法。这两种情况都可能造成阻塞。例如,IsCallAllowed可能需要查询数据库。当使用Select方法创建多个这样的任务并将结果枚举传递给Task.WhenAll方法时,这些延迟相加。在这种情况下,说任务同时启动可能并不准确。@TheodorZoulias,幸运的是,此方法访问一个静态ConcurrentDictionary对象。在这种情况下,行wait Task.WhenallObjectId.Selectid=>GetObjectInfo;将几乎同时启动所有任务。可能重复:我们所知道的是,将同步创建一组任务。我们可以假设它们将在热状态下创建,换句话说,它们已经开始创建,并且它们的创建速度足够快,可以认为是同步的。但我们需要查看GetObjectInfo的代码才能确定。哪一个BTW应该命名为GetObjectInfo async。因此任务是热的,因为它们是由异步方法创建的。每个任务的创建都涉及到节流器对象的创建,并调用其IsCallAllowed方法。这两种情况都可能造成阻塞。例如,IsCallAllowed可能需要查询数据库。创建多个
通过使用Select方法并将结果可枚举项传递给Task.whalll方法,这些延迟将相加。在这种情况下,说任务同时启动可能并不准确。@TheodorZoulias,幸运的是,此方法访问一个静态ConcurrentDictionary对象。在这种情况下,行wait Task.WhenallObjectId.Selectid=>GetObjectInfo;将几乎同时启动所有任务。因此,从任务执行的角度来看,在不考虑一致性错误和异常的情况下,foreach的代码块几乎等同于whalll?因为它会在短时间内创建大量任务,这些任务将根据系统调度程序进行处理-就像在WhenAll构造中一样?事实并非如此。带有wait关键字的for语句将按顺序运行任务。因此,如果顺序是不相关的,那么“当一切都好起来时”,因为它会更快地结束。顺序意味着下一个任务将仅在上一次完成后开始?正是这样。task类下没有任何任务。即使是Microsoft文档也有与您几乎相同的示例。您可以在列表中使用for each,但它不会有太大区别。因此,从任务执行的角度来看,在不考虑一致性错误和异常的情况下,使用foreach的代码块几乎等同于使用WhenAll的代码块?因为它会在短时间内创建大量任务,这些任务将根据系统调度程序进行处理-就像在WhenAll构造中一样?事实并非如此。带有wait关键字的for语句将按顺序运行任务。因此,如果顺序是不相关的,那么“当一切都好起来时”,因为它会更快地结束。顺序意味着下一个任务将仅在上一次完成后开始?正是这样。task类下没有任何任务。即使是Microsoft文档也有与您几乎相同的示例。你可以对列表中的每一个都使用一个,但这不会有多大区别。
using (var throttler = new Throttler(clientId))
{
while (!throttler.IsCallAllowed(out var waitTime))
{
await Task.Delay(waitTime);
}
var response = await client.PerformHttpRequestAsync(request);
return response.Content.FromJson<TResponse>(serializerSettings);
}