简体   繁体   English

具有连续性的简单并行任务

[英]Simple Parallel Tasks with Continuation

I have been reading for the 2 hours and I am still confused. 我已经阅读了两个小时,但我仍然感到困惑。 Some say use StartNew, some say Task.Run some say something else. 有人说使用StartNew,有人说Task。运行有人说其他。 I do know that Task.Run is giving me a compile error. 我确实知道Task.Run给我一个编译错误。

I need to start multiple tasks in parallel and then when each completes successfully do a continuation task. 我需要并行启动多个任务,然后在每个任务成功完成后执行一个继续任务。 Knowing when all are done with blocking would be helpful. 知道何时完成所有阻塞操作将很有帮助。

Here is what I have: 这是我所拥有的:

    public void DoSomeWork(object workItem)
    {
        var tasks = new Task<ResultArgs>[_itemList.Count];

        for (int loopCnt = 0; loopCnt < _itemList.Count; loopCnt++)
        {
            tasks[loopCnt] = new Task<ResultArgs>.Run(() =>
            {
                return _itemList[loopCnt].Analyze(workItem);
            });
            tasks[loopCnt].ContinueWith(ReportResults, TaskContinuationOptions.ExecuteSynchronously);
        }
    }

The compile says Run does not exist in Task. 编译显示“任务”中不存在“运行”。

Obviously, I have something run but I do not know what. 显然,我正在运行某些东西,但我不知道该怎么办。

How do I get past this problem? 我如何克服这个问题?

You can either do with async methods or you can flow your items into a dataflow the following code uses Tpl-dataflow to process your items, passes them to your second processing step and finally await completion of processing. 您可以使用async方法,也可以将项目流到数据流中,以下代码使用Tpl-dataflow处理项目,将其传递到第二个处理步骤,最后等待处理完成。

using NUnit.Framework;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;

namespace AsyncProcessing {

    [TestFixture]
    public class PipelineTests {

        [Test]
        public async Task RunPipeline() {
            var pipeline = new MyPipeline();
            var data = Enumerable.Range(0, 1000).Select(x => new WorkItem(x, x));

            foreach(var item in data) {
                await pipeline.SendAsync(item);
            }

            pipeline.Complete();
            await pipeline.Completion;

            //all processing complete            
        }
    }

    class MyPipeline {

        private BufferBlock<WorkItem> inputBuffer;
        private TransformBlock<WorkItem, WorkItem> analyzeBlock;
        private TransformBlock<WorkItem, ResultArg> reportBlock;
        private ActionBlock<ResultArg> postOutput;

        public ConcurrentBag<ResultArg> OutputBuffer { get; }
        public Task Completion { get { return postOutput.Completion; } }

        public MyPipeline() {
            OutputBuffer = new ConcurrentBag<ResultArg>();
            CreatePipeline();
            LinkPipeline();
        }

        public void Complete() {
            inputBuffer.Complete();
        }

        public async Task SendAsync(WorkItem data) {
            await inputBuffer.SendAsync(data);
        }

        public void CreatePipeline() {
            var options = new ExecutionDataflowBlockOptions() {
                MaxDegreeOfParallelism = Environment.ProcessorCount,
                BoundedCapacity = 10
            };

            inputBuffer = new BufferBlock<WorkItem>(options);

            analyzeBlock = new TransformBlock<WorkItem, WorkItem>(item => {
                //Anylyze item....
                return item;
            }, options);

            reportBlock = new TransformBlock<WorkItem, ResultArg>(item => {
                //report your results, email.. db... etc.
                return new ResultArg(item.JobId, item.WorkValue);
            }, options);

            postOutput = new ActionBlock<ResultArg>(item => {
                OutputBuffer.Add(item);
            }, options);
        }

        public void LinkPipeline() {
            var options = new DataflowLinkOptions() {
                PropagateCompletion = true,
            };

            inputBuffer.LinkTo(analyzeBlock, options);
            analyzeBlock.LinkTo(reportBlock, options);
            reportBlock.LinkTo(postOutput, options);
        }
    }

    public class WorkItem {

        public int JobId { get; set; }
        public int WorkValue { get; set; }

        public WorkItem(int id, int workValue) {
            this.JobId = id;
            this.WorkValue = workValue;
        }
    }

    public class ResultArg {

        public int JobId { get; set; }
        public int Result { get; set; }

        public ResultArg(int id, int result) {
            this.JobId = id;
            this.Result = result;
        }
    }
}

Why don't use Parallel.ForEach Loop. 为什么不使用Parallel.ForEach循环。 This is used for parallel executing tasks, It can use multiple Threads and Execution is faster Parallet.Foreach 这用于并行执行任务,它可以使用多个线程,执行速度更快的Parallet.Foreach

however it might fail if you are doing some database related input-output operation where locking is involves. 但是,如果您要进行一些涉及锁定的数据库相关的输入输出操作,则可能会失败。 In that case i would suggest in each task keep a return type and based on return type for previous task enable the ext task. 在那种情况下,我建议在每个任务中保留一个返回类型,并根据上一个任务的返回类型启用ext任务。

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

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