C# 将任务与延续链接,然后运行并行任务
并行任务的工作流程 我希望在我面临的问题上得到帮助。所以问题是我正在运行并行任务来搜索文件夹中的文件。每个任务都需要识别文件并将其添加到文件数组中。接下来,等待每个任务完成,以便收集文件,然后对结果进行排序。接下来,独立地处理排序后的文件,通过对每个文件运行一个任务来读取它,以获得匹配的模式。最后一个阶段是以人类可读的格式将所有结果聚合在一起,并以用户友好的方式显示 所以问题是,我希望以一种不会阻塞UI线程的适当方式链接任务。我希望能够在计划的任何阶段取消所有内容。 总而言之: 阶段1:通过搜索文件夹查找文件。每个任务通过文件夹树进行递归搜索 阶段2:对找到的所有文件进行排序并清除重复文件 阶段3:启动新任务以独立处理文件。每个任务打开一个文件并搜索匹配的模式 第四阶段:将每个文件搜索的结果聚合成一个巨大的结果集,并使其美观易读C# 将任务与延续链接,然后运行并行任务,c#,concurrency,parallel-processing,task-parallel-library,cancellationtokensource,C#,Concurrency,Parallel Processing,Task Parallel Library,Cancellationtokensource,并行任务的工作流程 我希望在我面临的问题上得到帮助。所以问题是我正在运行并行任务来搜索文件夹中的文件。每个任务都需要识别文件并将其添加到文件数组中。接下来,等待每个任务完成,以便收集文件,然后对结果进行排序。接下来,独立地处理排序后的文件,通过对每个文件运行一个任务来读取它,以获得匹配的模式。最后一个阶段是以人类可读的格式将所有结果聚合在一起,并以用户友好的方式显示 所以问题是,我希望以一种不会阻塞UI线程的适当方式链接任务。我希望能够在计划的任何阶段取消所有内容。 总而言之: 阶段1:通过搜
List<Task> myTasks = new List<Task>();
// ==== stage 1 ======
for(int i = 0; i < 10; i++) {
string directoryName = directories[i];
Task t = new Task(() =>
{
FindFiles(directoryName);
});
myTasks.Add(t);
t.Start();
}
// ==== stage 2 ====
Task sortTask = Task.Factory.ContinueWhenAll(myTasks.ToArray(), (t) =>
{
if(_fileResults.Count > 1) {
// sort the files and remove any duplicates
}
});
sortTask.Wait();
// ==== stage 3 ====
Task tt = new Task(() =>
{
Parallel.For(0, _fileResults.Count, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = token, TaskScheduler = _taskScheduler },
(i, loopstate) => {
// 1. open file
// 2. read file
// 3. read file line by line
}
}
// == stage 4 ===
tt.ContinueWith((t) =>
{
// 1. aggregate the file results into one giant result set
// 2. display the giant result set in human readable format
}, token, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.FromCurrentSynchronizationContext());
tt.start();
List myTasks=new List();
//==第一阶段======
对于(int i=0;i<10;i++){
字符串directoryName=目录[i];
任务t=新任务(()=>
{
FindFile(目录名);
});
添加(t);
t、 Start();
}
//==第二阶段====
Task sortTask=Task.Factory.continuewhall(myTasks.ToArray(),(t)=>
{
如果(_fileResults.Count>1){
//对文件进行排序并删除任何重复项
}
});
sortTask.Wait();
//==第三阶段====
任务tt=新任务(()=>
{
Parallel.For(0,_fileResults.Count,new ParallelOptions{maxdegreeofpparallelism=Environment.ProcessorCount,CancellationToken=token,TaskScheduler=_TaskScheduler},
(i,循环状态)=>{
//1.打开文件
//2.读取文件
//3.逐行读取文件
}
}
//==第4阶段===
tt.ContinueWith((t)=>
{
//1.将文件结果聚合为一个巨大的结果集
//2.以人类可读的格式显示巨大的结果集
},标记,TaskContinuationOptions.OnlyOnRanToCompletion,TaskScheduler.FromCurrentSynchronizationContext());
tt.start();
不要同步等待任何任务完成。如果这些操作需要在先前创建的任务之后进行,请将这些工作添加为该任务的继续。您是否考虑过使用异步/wait
功能?从您的问题听起来,它非常适合您的需要。以下是it’使用它可以快速解决您的问题:
try
{
List<Task<File[]>> stage1Tasks = new List<Task<File[]>>();
// ==== stage 1 ======
for (int i = 0; i < 10; i++)
{
string directoryName = directories[i];
Task<File[]> t = Task.Run(() =>
{
return FindFiles(directoryName);
},
token);
stage1Tasks.Add(t);
}
File[][] files = await Task.WhenAll(stage1Tasks).ConfigureAwait(false);
// Flatten files.
File[] _fileResults = files.SelectMany(x => x).ToArray();
// ==== stage 2 ====
Task<File[]> sortFilesTask = Task.Run(() =>
{
if (_fileResults.Count > 1)
{
// sort the files and remove any duplicates
return _fileResults.Reverse().ToArray();
}
},
token);
File[] _sortedFileResults = await sortFilesTask.ConfigureAwait(false);
// ==== stage 3 ====
Task<SomeResult[]> tt = Task.Run(() =>
{
SomeResult[] results = new SomeResult[_sortedFileResults.Length];
Parallel.ForEach(_sortedFileResults,
new ParallelOptions {
MaxDegreeOfParallelism = Environment.ProcessorCount,
CancellationToken = token,
TaskScheduler = _taskScheduler
},
(i, loopstate) =>
{
// 1. open file
// 2. read file
// 3. read file line by line
results[i] = new SomeResult( /* here goes your results for each file */);
});
return results;
},
token);
SomeResult[] theResults = await tt.ConfigureAwait(false);
// == stage 4 ===
// 1. aggregate the file results into one giant result set
// 2. display the giant result set in human readable format
// ....
}
catch (TaskCanceledException)
{
// some task has been cancelled...
}
试试看
{
List STAGE1任务=新列表();
//==第一阶段======
对于(int i=0;i<10;i++)
{
字符串directoryName=目录[i];
Task t=Task.Run(()=>
{
返回FindFile(目录名);
},
代币);
阶段1任务。添加(t);
}
File[][]files=await Task.WhenAll(stage1Tasks.ConfigureAwait(false);
//展平文件。
File[]\u fileResults=files.SelectMany(x=>x).ToArray();
//==第二阶段====
Task sortFilesTask=Task.Run(()=>
{
如果(_fileResults.Count>1)
{
//对文件进行排序并删除任何重复项
返回_fileResults.Reverse().ToArray();
}
},
代币);
文件[]\u sortedFileResults=await sortFilesTask.ConfigureAwait(false);
//==第三阶段====
Task tt=Task.Run(()=>
{
SomeResult[]results=新的SomeResult[_sortedFileResults.Length];
并行。ForEach(_sortedFileResults,
新的并行选项{
MaxDegreeOfParallelism=Environment.ProcessorCount,
CancellationToken=令牌,
TaskScheduler=\u TaskScheduler
},
(i,循环状态)=>
{
//1.打开文件
//2.读取文件
//3.逐行读取文件
results[i]=newsomeresult(/*这里是每个文件的结果*/);
});
返回结果;
},
代币);
SomeResult[]theResults=await tt.ConfigureAwait(false);
//==第4阶段===
//1.将文件结果聚合为一个巨大的结果集
//2.以人类可读的格式显示巨大的结果集
// ....
}
捕获(TaskCanceledException)
{
//某些任务已被取消。。。
}
您不应该使用任务
构造函数。如果要创建表示执行委托的任务,请使用任务。运行
来创建和启动这样的任务。您不应该让这些任务中的每一个都改变列表
来添加它们的结果。列表
不是线程安全的,因此这不一定是安全的工作。让每个任务返回其计算结果时产生的值,并继续通过Task
API访问该结果。我使用lock和interlock对共享对象进行锁定。共享对象是结果集。在您发布的代码中不是。即使如此,您也不应该这样做。您应该让每个任务将其结果设置为其计算的值。它表示语义更好的是,它允许对代码进行模块化,并在隔离状态下进行有效的分析,而且它也会更快,因为您不会在每个任务之间引入完全不必要的依赖关系。我同意您的观点。一旦我弄清楚如何将任务链接在一起,我可能会相应地对其进行更改