依次处理任务 [英] Processing tasks sequentially

查看:37
本文介绍了依次处理任务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个基类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.

我阅读并尝试了 SequentialTask​​Scheduler,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.WaitAllList,如果您知道要等待多少个任务,这很好.它不能作为任务执行者"工作,因为不可能打断 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆