依次处理任务 [英] Processing tasks sequentially
问题描述
我有一个基类JobBase
,它有一个返回任务的方法Execute()
.有几个类继承自 JobBase
并执行一些异步操作.我需要将继承的类的实例放入一个列表中并按顺序执行它们,因此有 job1、job2、job3 等,job2 应在作业 1 完成时启动,作业 3 应在作业 2 完成时启动,以此类推.
i have a base class JobBase
that has a single method Execute()
which returns a Task. There are several classes that inherits from JobBase
and that do some asynchronous operations. I need to put instances of the inherited classes into a list and execute them sequentially, so having job1, job2, job3, etc. job2 shall start when job 1 is finished, job 3 shall start when job2 is finished, etc.
因此队列可能包含任意数量的作业.例如:job1 下载一些内容,job2 读取内容.在另一个场景中,job1 下载一些内容,job2 下载一些其他内容,job3 读取内容,等等.
So the queue may contain an arbitrary number of jobs. For example: job1 downloads some content, job2 reads the content. In an another scenario, job1 downloads some content, job2 downloads some other content, job3 reads the content, etc.
示例
// The base class
public abstract class JobBase
{
public abstract Task Execute();
}
// inherited jobs
public class Job1 : JobBase
{
public override Task Execute()
{
// this one: return Task.Run()
// or this one?:
Task task = new Task(async () =>
{
await Task.Delay(2000);
});
return task;
}
}
public class Job2 : JobBase
{
public override Task Execute()
{
Task task = new Task(async () =>
{
await Task.Delay(1000);
});
return task;
}
}
主程序:
private static void Main(string[] args)
{
var jobs = new List<JobBase>();
jobs.Add(new Job1());
jobs.Add(new Job2());
List<Task> tasks = new List<Task>();
for (int i = 0; i < jobs.Count; i++)
{
var jobNr = i;
Task task = jobs[jobNr].Execute();
tasks.Add(task);
task.Start();
}
Console.WriteLine("Starting WaitAll");
Task.WaitAll(tasks.ToArray());
Console.WriteLine("Finished");
Console.ReadKey();
}
实际上,任务已执行,我无法控制它们执行(或完成)的顺序.此外,如果前一个工作成功,我想获得每个工作的结果(布尔值)并继续下一个工作.
Actually, the tasks are executed and i have no control aboute the order they are executed (or finished). Additionally, I would like to get a result (bool) of each job and continue with the next job, if the previous one was successful.
我阅读并尝试了 SequentialTaskScheduler,TaskCompletionSource 的解决方案,关于 在任务完成时处理任务.由于作业(任务)数量未知,我无法使用 ContinueWith.
I read and tried the SequentialTaskScheduler, solutions with TaskCompletionSource, the tutorial about Processing tasks as they complete. I cannot work with ContinueWith since the number of jobs(tasks) is not known.
请查看以下示例及其输出.为简单起见,有一个 Job
类继承自 JobBase
,它接受一个索引和一个延迟值:
Please have a look at the following example and its output. For simplicity reasons there is one class Job
that inherits from JobBase
which takes an index and a delay value:
public class Job : JobBase
{
private readonly int _index;
private readonly int _delay;
public Job(int index, int delay)
{
_index = index;
_delay = delay;
}
public override Task Execute()
{
Task task = new Task(async () =>
{
Console.WriteLine("Job {0} before delay", _index);
await Task.Delay(_delay);
Console.WriteLine("Job {0} after delay", _index);
});
return task;
}
}
在任务列表中添加一些实例,如
Adding some instances to the task list, such as
jobs.Add(new Job(1, 3000));
jobs.Add(new Job(2, 2000));
jobs.Add(new Job(3, 1000));
我得到以下结果:
Starting WaitAll
Job 2 before delay
Job 3 before delay
Job 1 before delay
Finished
Job 3 after delay
Job 2 after delay
Job 1 after delay
(Job3首先完成,因为延迟小于job2等)
(Job3 finishes at first, since the delay is less than job2, etc.)
想要的结果是:
Starting WaitAll
Job 1 before delay
Job 1 after delay
Job 2 before delay
Job 2 after delay
Job 3 before delay
Job 3 after delay
Finished
顺序运行异步任务的最佳方法是什么?我可以随意更改 Execute 方法的签名,例如返回 Task 或其他任何内容.
What is the best approach to run the async tasks sequentially? I am free to change the signature of the Execute method, e.g returning Task or whatever.
推荐答案
所以队列...
什么队列?您当前的代码使用带有 Task.WaitAll
的 List
,如果您知道要等待多少个任务,这很好.它不能作为任务执行者"工作,因为不可能打断 WaitAll
并说哦,你现在有一个新任务".
What queue? Your current code uses a List<T>
with Task.WaitAll
, which is fine if you know how many tasks you're waiting for. It doesn't work as a "task runner", because it's not possible to interrupt the WaitAll
and say "oh, you have a new task now".
在我看来,您正在寻找的是 ActionBlock
:
It sounds to me like what you're looking for is ActionBlock<T>
:
private static void Main(string[] args)
{
var jobs = new ActionBlock<JobBase>(x => x.Execute());
jobs.Add(new Job1());
jobs.Add(new Job2());
jobs.Complete();
Console.WriteLine("Starting Wait");
Task.WaitAll(jobs.Completion.Wait()); // only using Wait because this code is in Main
Console.WriteLine("Finished");
Console.ReadKey();
}
ActionBlock
默认一次执行一个任务.
ActionBlock<T>
by default will execute one task at a time.
此外,如果前一个工作成功,我想获得每个工作的结果(布尔值)并继续下一个工作.
Additionally, I would like to get a result (bool) of each job and continue with the next job, if the previous one was successful.
如果您报告带有异常的错误,则 ActionBlock
将停止处理第一个失败的作业.
If you report errors with exceptions, then the ActionBlock
will stop processing on the first failed job.
这篇关于依次处理任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!