繁体   English   中英

如何使用负载均衡和有限并行度的任务并行库(TPL)?

[英]How to use task parallel library (TPL) with load balancing and limited degree of parallelism?

我的任务是使用(异步)接口将已知的nr值写入外部系统。 我必须限制并发执行的最大并行写入次数。 此外,我必须使用负载平衡,因为该外部系统可能需要更长的时间来写入某些值。

我知道如何解决这些问题本身:

并行度:

new ParallelOptions {MaxDegreeOfParallelism = maxNrParallelWrites}

我也偶然发现了这篇文章: http//msdn.microsoft.com/en-us/library/ee789351(v = vs.110).aspx

负载均衡:

var partitioner = Partitioner.Create(values.ToList(), true);

来自异步接口的任务:

var writeTask = Task<AccessResult>.Factory.FromAsync(BeginWriteValue, EndWriteValue, value.SystemId, value.Xml, priority, null);



但是,我如何正确地结合所有这些技术? 我创建了以下代码:

  int maxNrParallelWrites = GetMaxNrParallelWrites();
  var partitioner = Partitioner.Create(values.ToList(), true);
  Parallel.ForEach(partitioner, new ParallelOptions {MaxDegreeOfParallelism = maxNrParallelWrites},
    (val) =>
    {
      var writeValueTask = GetWriteValueTask(val, priority);
      Task.WaitAny(writeValueTask);
    });

我特别不确定上一代码的最后一部分:执行工作负载的操作。 是否更好,而不是创建一个WriteValueTask直接使用这样的同步接口:

(val) =>
    {
      var accessResult = externalSystem.WriteValue(....);
    }

或者可以创建一个任务然后直接等待它(Task.WaitAny(...))?

您应该使用TPL Dataflow的ActionBlock来封装所有这些内容。 这是一个基于actor的框架,是TPL的一部分:

var block = new ActionBlock<Value>(
    value => GetWriteValueTask(value, priority)
    new ExecutionDataflowBlockOptions()
    {
        MaxDegreeOfParallelism = GetMaxNrParallelWrites();
    });

foreach (var value in values)
{
    block.Post(value);
}

您可以设置MaxDegreeOfParallelismBoundedCapacity和负载均衡,因为它一次只处理MaxDegreeOfParallelism项目,每次完成时它处理下一个项目(而不是使用预先分区集合的Partitioner程序)

注意:当您执行async任务并等待它同步完成时(即Task.WaitAny )实际上没有任何异步。 在这种情况下,你应该使用Task.WhenAny

本文中有一个很好的示例,说明如何创建负载平衡ForEachASync方法 我已经取出Task.Run以避免启动新线程,然后扩展方法变为:

public static class Extensions
{
    public static async Task ExecuteInPartition<T>(IEnumerator<T> partition, Func<T, Task> body)
    {
        using (partition)
            while (partition.MoveNext())
                await body(partition.Current);
    }

    public static Task ForEachAsync<T>(this IEnumerable<T> source, int dop, Func<T, Task> body)
    {
        return Task.WhenAll(
            from partition in Partitioner.Create(source).GetPartitions(dop)
            select ExecuteInPartition(partition, body));
    }
}

用法

此示例一次异步处理最多100封电子邮件

 // Process 100 emails at a time
 return emailsToProcess.ForEachAsync(100, ProcessSingleEmail);

暂无
暂无

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

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