Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Defer starting of a Task<T>

I have a series of methods (with variable number of parameters) that return a Task I want to create a method that does something before and after each of this methods, by passing the Task. I've simplified everything (removed cancellationToken, actual processing, etc) in this sample:

public async Task<string> GetDataString()
{
    Console.WriteLine("Executing");
    return "test";
}


public async Task<T> Process<T>(Task<T> task)
{
    Console.WriteLine("Before");
    var res = await task;
    Console.WriteLine("After");
    return res;
}

And in my main:

Task<string> task = GetDataString();
string result = await Process<string>(tasks);
Console.WriteLine(res);

the console output is

Executing
Before
After
test

What can I do to create the task but not actually starting it? And starting it only before the wait?

I managed to do it by creating a PauseToken, as explained in this article: https://devblogs.microsoft.com/pfxteam/cooperatively-pausing-async-methods/ but I wonder if is there a better way.

Thanks, Mattia

like image 525
Mattia Durli Avatar asked Nov 29 '19 10:11

Mattia Durli


People also ask

What is Task delay?

The Delay method is typically used to delay the operation of all or part of a task for a specified time interval. Most commonly, the time delay is introduced: At the beginning of the task, as the following example shows.

What does Task t mean?

A completed Task does not contain any sort of result, it just represents the fact that the operation has finished. Task<T> also represents an operation which might be in progress, or might have been cancelled, faulted, or might have completed.

What happens if you don't await a Task?

If you don't await the task or explicitly check for exceptions, the exception is lost. If you await the task, its exception is rethrown. As a best practice, you should always await the call. By default, this message is a warning.

What is Task yield ()?

You can use await Task. Yield(); in an asynchronous method to force the method to complete asynchronously. If there is a current synchronization context (SynchronizationContext object), this will post the remainder of the method's execution back to that context.


1 Answers

Your generic ProcessAsync method could accept a task factory as argument:

public async Task<T> ProcessAsync<T>(Func<Task<T>> taskFactory)
{
    Console.WriteLine("Before");
    var res = await taskFactory();
    Console.WriteLine("After");
    return res;
}

This way the task will be created at the time you'll invoke the factory method. You are in control of its creation.

Here is an example of calling the ProcessAsync method, passing as factory a lambda:

var result = await ProcessAsync(() => GetDataStringAsync(arg1, arg2));

This way you are not restricted to a factory method without arguments.

For completeness I should mention that Task objects can also created in a cold state using the constructor new Task(), and started later using the Start method, but this approach is not recommended.

like image 61
Theodor Zoulias Avatar answered Oct 19 '22 12:10

Theodor Zoulias