繁体   English   中英

如何在多个并发请求中实现并行度恒定的异步并行任务执行?

[英]How to implement asynchronous parallel task executions with degree of parallelism constant across multiple concurrent requests?

我的 API 采用需要处理的项目(不同类型)的集合。

public class Collection
{
   public List<ItemType1> Type1Items {get; set;}
   public List<ItemType2> Type2Items {get; set;}
   public List<ItemType3> Type3Items {get; set;}
   public List<ItemType4> Type4Items {get; set;}
   .
   .
   .
}

请求处理程序将此Collection传递给ItemsProcesser ItemsProcessor进一步划分集合(基于类型)并在每个组上调用外部 API。 例如,一个包含 4 种不同类型项目的集合的传入请求被分解为具有特定类型项目的四个集合,从而导致 4 次外部 API 调用。

所以基本上, Collection类型用于表示具有多种类型的实例以及包含特定类型项目的分解实例。

传入请求中的集合可以包含最多属于 20 种不同类型的项目。 因此,我的处理可能涉及每个传入请求的 1 到 20 个下游 API 调用。 我想并行执行这些下游请求,以减少传入请求的响应时间。

/// CollectionHandler.cs
public override async Task ProcessRequestAsync(HttpContext context)
{
    var request = context.Request;
    var collectionToProcess = GetCollection(request);
    var processor = new ItemsProcessor()
    await processor.ExecuteAsync(collectionToProcess);
}
/// ItemsProcessor.cs
public async Task ExecuteAsync(Collection collection)
{
    foreach(var (typeName, collection) in collection.GroupByTypes())
    {
       await downstreamClient.ExecuteAsync(collection, type);
    }
}
/// ApiClient.cs
public async Task ExecuteAsync(Collection collection, string collectionType)
{
    // Validate that the collection input parameter
    // only has items of type name collectionType
    var isValid = collection.Validate(collectionType);
    if (!isValid)
    {
       throw new ValidationFailedException();
    }

    // Use collection in request body and
    // collection type as request parameter.
    var restRequest = GetRequest(collection, type);
    await restClient.ExecuteTaskAsync(restRequest);
}

为每个实现异步并行并不是什么大问题。 但是,即使该实现支持一定程度的并行性或限制,多个并发传入请求也会并行调用ItemsProcessor ,并且每个请求都会扇出多个下游 API 调用。

如何确保无论有多少并发呼入,对下游服务的并行调用数都不会超过某个最大限制?

一个可能的解决方案是使用Polly库中的Bulkhead策略:

using Polly;
private static IAsyncPolicy _policy = Policy.BulkheadAsync(
    maxParallelization: 20, maxQueuingActions: Int32.MaxValue);
  • maxParallelization是可以通过策略同时执行的最大操作数。
  • maxQueuingActions是达到前一个限制时可以排队等待执行槽的最大操作数。 超出此限制,将引发BulkheadRejectedException

然后替换这一行:

await processor.ExecuteAsync(collectionToProcess);

...有了这个:

await _policy.ExecuteAsync(async () =>
{
    await processor.ExecuteAsync(collectionToProcess);
});

只要您的服务在单个进程上运行,就会强制执行该策略。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM