簡體   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