How to delay 'hot' tasks so they can proce

2020-03-30 03:42发布

Say I have a set of tasks:

        var task1 = DoThisAsync(...);
        var task2 = DoThatAsync(...);
        var task3 = DoOtherAsync(...);
        var taskN...

I am looking for a way to process a set of tasks in order (determined by place in containing collection say), but to have the tasks only run/start when its their turn and not before - and have all of that wrapped up in its own task.

Problem constraints / details are:

  1. These tasks need to be performed in a certain order i.e.task1, task2,...
  2. The previous task must complete asynchronously before the next can start
  3. The number of tasks is variable
  4. A different set of tasks may be nominated each time code is run
  5. The order and number of tasks is known in advance.

The main problem is that as soon as I call the relevant method (like DoThis()...) to return each task, that task is already 'hot' or running, violating (2) above.

I have tried working with.ContinueWith(..) , but if I call each of tasks like above to set the continuations or add them to a list or collection they've already started.

Not sure if Lazy < T > might help but can't see how at present?

Hope this makes sense as I'm fairly new to async / await / tasks.

Many thanks in advance.

2条回答
啃猪蹄的小仙女
2楼-- · 2020-03-30 04:23

you can simply create tasks with its constructor and then, call execution with .Start() methods.

Here an example:

var taskList = InitQueue();
foreach (var t in taskList.OrderBy(i => i.Order))
{
    //Here I can skedule an existing task
    t.TaskToRun.Start();
    t.TaskToRun.Wait();
    Console.WriteLine($"Task {t.Order} has finished its job");
}


public class TaskQueue : List<TaskItem>
{
}

public class TaskItem
{
    public int Order { get; set; }
    public Task TaskToRun { get; set; }
}

private static TaskQueue InitQueue()
{
    var queue = new TaskQueue();
    queue.Add(new TaskItem
    {
        Order = 1,
        TaskToRun = new Task(() =>
        {
            Task.Delay(500);
            Console.WriteLine("Hello from task 1");
        })
    });
    queue.Add(new TaskItem
    {
        Order = 4,
        TaskToRun = new Task(() => Console.WriteLine("Hello from task 4"))
    });
    queue.Add(new TaskItem
    {
        Order = 3,
        TaskToRun = new Task(() =>
        {
            Task.Delay(5000);
            Console.WriteLine("Hello from task 3");
        })
    });
    queue.Add(new TaskItem
    {
        Order = 2,
        TaskToRun = new Task(() => Console.WriteLine("Hello from task 2"))
    });

    return queue;
}
查看更多
太酷不给撩
3楼-- · 2020-03-30 04:39

Calling a method runs code. If you want an object that will call this method later, then use a delegate.

In this case, you could use Func<Task>, which is an asynchronous delegate. A list of these should suffice:

// Build the list of operations in order.
var operations = new List<Func<Task>>();
operations.Add(() => DoThisAsync(...));
operations.Add(() => DoThatAsync(...));
operations.Add(() => DoOtherAsync(...));

// Execute them all one at a time.
foreach (var operation in operations)
  await operation();
查看更多
登录 后发表回答