C# 带延续的简单并行任务
我已经读了两个小时了,我仍然很困惑。有人说使用StartNew,有人说Task,有人说运行,有人说其他。我知道Task.Run给了我一个编译错误 我需要并行启动多个任务,然后在每个任务成功完成后,执行一个继续任务。知道什么时候所有的阻塞都完成了会很有帮助 以下是我所拥有的:C# 带延续的简单并行任务,c#,c#-4.0,task-parallel-library,C#,C# 4.0,Task Parallel Library,我已经读了两个小时了,我仍然很困惑。有人说使用StartNew,有人说Task,有人说运行,有人说其他。我知道Task.Run给了我一个编译错误 我需要并行启动多个任务,然后在每个任务成功完成后,执行一个继续任务。知道什么时候所有的阻塞都完成了会很有帮助 以下是我所拥有的: public void DoSomeWork(object workItem) { var tasks = new Task<ResultArgs>[_itemList.Count
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);
}
}
public void DoSomeWork(对象工作项)
{
var tasks=新任务[_itemList.Count];
对于(int-loopCnt=0;loopCnt<\u itemList.Count;loopCnt++)
{
tasks[loopCnt]=新任务。运行(()=>
{
返回_itemList[loopCnt].Analyze(workItem);
});
任务[loopCnt].ContinueWith(ReportResults,TaskContinuationOptions.ExecuteSynchronously);
}
}
编译程序表示任务中不存在运行
很明显,我有些事情要做,但我不知道要做什么
如何克服此问题?为什么不使用Parallel.ForEach循环。这用于并行执行任务,它可以使用多个线程,执行速度更快
但是,如果您正在执行一些涉及锁定的与数据库相关的输入输出操作,则可能会失败。在这种情况下,我建议在每个任务中保留一个返回类型,并基于上一个任务的返回类型启用下一个任务。您可以使用
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;
}
}
}
使用NUnit.Framework;
使用制度;
使用System.Collections.Concurrent;
使用System.Linq;
使用System.Threading.Tasks;
使用System.Threading.Tasks.Dataflow;
命名空间异步处理{
[测试夹具]
公共类管道测试{
[测试]
公共异步任务RunPipeline(){
var pipeline=new MyPipeline();
var data=Enumerable.Range(0,1000)。选择(x=>newworkItem(x,x));
foreach(数据中的var项){
等待管道发送异步(项目);
}
管道。完成();
等待管道完工;
//所有处理完成
}
}
类MyPipeline{
专用缓冲块输入缓冲区;
私人密码锁;
私有转换块报告块;
私有操作块输出;
公共ConcurrentBag输出缓冲区{get;}
公共任务完成{get{return postOutput.Completion;}}
公共管道(){
OutputBuffer=新的ConcurrentBag();
CreatePipeline();
链接管道();
}
公开作废完成(){
inputBuffer.Complete();
}
公共异步任务SendAsync(工作项数据){
等待inputBuffer.SendAsync(数据);
}
公共管道(){
var options=new ExecutionDataflowBlockOptions(){
MaxDegreeOfParallelism=Environment.ProcessorCount,
边界容量=10
};
inputBuffer=新的缓冲块(选项);
analyzeBlock=新转换块(项=>{
//任意项目。。。。
退货项目;
},选项);
reportBlock=新的TransformBlock(项=>{
//报告您的结果,发送电子邮件..db…等。
返回新的ResultArg(item.JobId、item.WorkValue);
},选项);
postOutput=新操作块(项=>{
OutputBuffer.Add(项);
},选项);
}
公共管道(){
var options=new DataflowLinkOptions(){
完成=真,
};
inputBuffer.LinkTo(解析块,选项);
analyzeBlock.LinkTo(报告块,选项);
链接到(postOutput,选项);
}
}
公共类工作项目{
public int JobId{get;set;}
公共int工作值{get;set;}
公共工作项(int id,int workValue){
this.JobId=id;
this.WorkValue=WorkValue;
}
}
公共类结果目标{
public int JobId{get;set;}
公共int结果{get;set;}
public ResultArg(int-id,int-result){
this.JobId=id;
结果=结果;
}
}
}
我最终使用了你提出的异步方法。我想我是对的,因为编译器没有大惊小怪。我们将在我开始测试时发现!我还将研究我以前从未见过的TPL数据流。参见数据流速成课程的编辑:)也谢谢!更多的阅读!斯蒂芬的作品通常都很好,值得一读。谢谢你的链接!我曾考虑过Parallel.ForEach,但被警告它不会将我的所有任务都放在准备运行队列中。它会限制每次的数量,因为接近实时的限制,我担心吞吐量。然而,这确实提醒了我,我需要担心异常@AeroClassicsasync
如果使用defalt任务调度器,也有类似的限制。这不是我真正想听到的,而是我需要知道的。谢谢<代码>任务.运行仅存在于4.5中,不存在于4.0中。