2

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.

Cleve
  • 1,273
  • 1
  • 13
  • 26
  • Can't you just await each? – sellotape Oct 19 '16 at 10:43
  • @sellotape, no can't await each as tasks in question can vary, so need to add to collection and then process. But adding to a collection means calling DoThisAsync(..) etc. which sets tasks running which I don't want. – Cleve Oct 19 '16 at 10:48
  • If you have to do it that way, there are (limited) options for creating Tasks without starting them. See http://stackoverflow.com/questions/16066349/how-to-construct-a-task-without-starting-it – sellotape Oct 19 '16 at 10:53
  • Why would calling `DoThisAsync()` run the Task? If you create a Task and return it, it won't run unless you put it into a running state, e.g. by using `Task.Run()` – Krumelur Oct 19 '16 at 12:00
  • 1
    @Krumelur - assuming modern naming conventions, a method called XxxAsync() *should* always return a hot task. If you use e.g. `async`/`await` to implement the method, then this will always be true, but as I say, it's also the convention no matter how the method is implemented. – Damien_The_Unbeliever Oct 19 '16 at 12:12
  • True that is. My question was more whether he has control of those methods and can influence the state. – Krumelur Oct 19 '16 at 12:14
  • @Krumelur , no I can't influence the state. They return running. – Cleve Oct 19 '16 at 12:32

2 Answers2

9

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();
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
-1

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;
}
Glauco Cucchiar
  • 764
  • 5
  • 19