优化并行选择,实现并行执行

时间:2015-01-08 09:39:16

标签: c# parallel-processing plinq

我试图找到执行以下流程的最佳方式

  1. 从流程中获取X标识符列表
  2. 对于每个X标识符,请转到DB并使用复杂查询获取Y标识符列表(应并行
  3. 合并列表并区分它
  4. 对于每个Y标识符执行一个长时间运行的任务(应该并行
  5. 2-4中的所有流程都应该在与1不同的线程中完成,这样一旦动作1调用动作2,它就会继续做其他事情。

    目前我的流程看起来像这样(这是2-4并在1之后调用):

    private void PerformActionAsync(List<long> XIds)
    {
         var affectedYIds = XIds.AsParallel().SelectMany(xId =>
         {
             return GetAffectedYIdsLongRunning(xId);   
    
         }).Distinct();
    
         affectedYIds.ForAll(yId=>
         {
             ExcuteLongRunningAction(yId);
         });
     }
    

    这不起作用,因为SelectMany和ForAll仍然阻止调用线程,我可以用新任务创建替换ForAll但仍然SelectMany将阻塞调用线程。 如何以真正的异步方式执行SelectMany?

    目前我最好的解决方案是用Taks.Run包装整个方法实现,问题是如果有更好的方法。

1 个答案:

答案 0 :(得分:1)

您可以将代码包装在Task.Run中并返回该任务。这将使一切都在后台运行。

以下单元测试显示用法:

[TestClass]
public class PLinqTests
{
    private static readonly Stopwatch Watch = Stopwatch.StartNew();

    [TestMethod]
    public async Task TestPerformAsync()
    {
        await PerformActionAsync(Enumerable.Range(0, 10));
    }

    private Task PerformActionAsync(IEnumerable<int> xIds)
    {
        return Task.Run(() =>
        {
            var affectedYIds = xIds
                .AsParallel()
                .WithDegreeOfParallelism(5)
                .SelectMany(this.GetAffectedYIdsLongRunning)
                .Distinct();

            affectedYIds.ForAll(this.ExcuteLongRunningAction);
        });
    }

    private void ExcuteLongRunningAction(int yId)
    {
        Thread.Sleep(1000);
        Console.WriteLine("Executed {0} at {1}.", yId, Watch.Elapsed.Seconds);
    }

    private IEnumerable<int> GetAffectedYIdsLongRunning(int xId)
    {
        Thread.Sleep(1000);
        Console.WriteLine("Getting Affected for {0} at {1}.", xId, Watch.Elapsed.Seconds);

        return Enumerable.Range(30, 10);
    }
}

输出:

Getting Affected for 0 at 1.
Getting Affected for 1 at 1.
Getting Affected for 2 at 1.
Getting Affected for 4 at 2.
Getting Affected for 3 at 2.
Getting Affected for 5 at 2.
Getting Affected for 6 at 2.
Getting Affected for 7 at 3.
Getting Affected for 8 at 3.
Getting Affected for 9 at 3.
Executed 32 at 3.
Executed 31 at 3.
Executed 30 at 4.
Executed 34 at 4.
Executed 33 at 4.
Executed 37 at 4.
Executed 36 at 4.
Executed 35 at 5.
Executed 39 at 5.
Executed 38 at 5.