我有一个基类JobBase
,它有一个返回任务的方法Execute()
。有几个类继承自JobBase
并执行一些异步操作。我需要将继承类的实例放入列表并按顺序执行,因此job1,job2,job3等job2将在作业1完成时启动,作业3将在job2完成时启动等等。
因此队列可能包含任意数量的作业。 例如:job1下载一些内容,job2读取内容。在另一种情况下,job1下载一些内容,job2下载一些其他内容,job3读取内容等。
示例
// 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();
}
实际上,任务已执行,我无法控制它们执行(或完成)的顺序。另外,如果前一个工作成功,我想得到每个工作的结果(bool)并继续下一个工作。
我阅读并尝试了SequentialTaskScheduler,解决方案和TaskCompletionSource,关于Processing tasks as they complete的教程。 由于工作(任务)的数量未知,我无法使用ContinueWith。
请查看以下示例及其输出。为简单起见,有一个类Job
继承自JobBase
,它接受一个索引和一个延迟值:
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;
}
}
将一些实例添加到任务列表中,例如
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等)
期望的结果是:
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或其他任何内容。
答案 0 :(得分:0)
试试这个:
async void Main(string[] args)
{
var jobs = new List<JobBase>();
jobs.Add(new Job(1, 3000));
jobs.Add(new Job(2, 2000));
jobs.Add(new Job(3, 1000));
for (int i = 0; i < jobs.Count; i++)
{
var t = jobs[i].Execute();
await t;
}
Console.WriteLine("Finished");
Console.ReadLine();
}
请注意,我们不再使用
Task.WaitAll(tasks.ToArray());
因为这允许任务并行运行。我们只是在循环中等待他们。
将Job类修改为:
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 = Task.Run(async () =>
{
Console.WriteLine("Job {0} before delay", _index);
await Task.Delay(_delay);
Console.WriteLine("Job {0} after delay", _index);
});
return task;
}
}
请注意
的更改Task task = new Task(async () =>
到
Task task = Task.Run(async () =>
答案 1 :(得分:0)
所以队列......
什么队列?您当前的代码使用DROP + CREATE + INSERT INTO
List<T>
,如果您知道等待了多少任务,那就没问了。它不能作为“任务跑步者”,因为不可能打断Task.WaitAll
并说“哦,你现在有一项新任务”。
听起来像你正在寻找的是ActionBlock<T>
:
WaitAll
默认情况下, 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();
}
将一次执行一项任务。
此外,如果上一份工作成功,我希望获得每项工作的结果(bool)并继续下一份工作。
如果您报告包含例外的错误,则ActionBlock<T>
将停止处理第一个失败的作业。