I have the following code:
public Index () {
InitializeIndexAsync();
}
async Task InitializeIndexAsync () {
State = IndexState.Initializing;
await Task.Factory.StartNew(async () => {
// Initialize other things.
await IndexAsync();
});
State = IndexState.Ready;
}
I would expect that "State = IndexState.Ready" would not be hit until the asynchronous lambda completes, but debugging shows that line is hit long before the thread started above it completes. Why is this?
StartNew does not understand async lambdas, so when you pass it an async lambda, it will return a Task<Task>. Conceptually, the "outer" task only represents the start of the async lambda; the "inner" task represents the completion of the async lambda.
This is one of the reasons that StartNew is the wrong choice for async code, as I explain on my blog. A better solution is to use Task.Run, which was designed with async in mind:
async Task InitializeIndexAsync () {
State = IndexState.Initializing;
await Task.Run(async () => {
// Initialize other things.
await IndexAsync();
});
State = IndexState.Ready;
}
Not sure what you are trying to achieve by all these awaits...
I would try to keep it simple by having a synchronously method which initializes things, and then another MethodAsync which returns a Task and I can await on that task:
public async void Index()
{
await InitializeIndexAsync();
}
private Task InitializeIndexAsync()
{
return Task.Factory.StartNew(() => InitializeIndex());
}
private void InitializeIndex()
{
State = IndexState.Initializing;
// Initialize other things synchronously.
IndexAsync().Wait();
State = IndexState.Ready;
}
I hope this is what you meant.
Related
I am starting a Thread where an await Task.Run can be invoked.
After starting a Thread with the ThreadStart.Start method, why does the await Task.Run terminate the Thread and Task.Run does not?
Here is some code as an example:
public async Task Task1()
{
if (awaitRunTask)
{
await Task.Run(async () =>
{
await Test();
}
);
}
else
{
Task.Run(async () =>
{
await Test();
}
);
}
}
In the above example, if a Thread invokes the Task1 method, and awaitRunTask = true, the Thread terminates. If awaitRunTask = false, the Thread does not terminate.
When I say terminate, the Thread does not complete correctly and the method where the ThreadStart.Start is invoked returns. This happens at the await Test() code.
Why is this and if I want to await a Task.Run on a Thread, is there a way to do this?
EDIT
Here is some code to show a more detailed example:
public class ThreadExample
{
public bool awaitRunTask;
public string value;
private async Task StartThreadAsync()
{
var method = this.GetType().GetMethod("RunTasksAsync");
ThreadStart threadStart;
threadStart = async () =>
{
await InvokeAsync(method, this, null);
};
var thread = new Thread(threadStart);
thread.Start();
thread.Join();
}
public async Task RunTasksAsync()
{
await Task1Async();
Task2();
}
private async Task Task1Async()
{
if (awaitRunTask)
{
await Task.Run(async () =>
{
await TestAsync();
}
);
}
else
{
Task.Run(async () =>
{
await TestAsync();
}
);
}
}
private void Task2()
{
value = "valid";
}
private async Task TestAsync()
{
await Task.Delay(1000);
}
private async Task InvokeAsync(MethodInfo method, object instance, object[] parameters)
{
dynamic awaitable = method.Invoke(instance, parameters);
await awaitable;
}
public async Task ValueIsCorrectAsync()
{
value = "not valid";
awaitRunTask = false;
await StartThreadAsync();
var isCorrect = (value == "valid");
}
public async Task ValueIsNotCorrectAsync()
{
value = "not valid";
awaitRunTask = true;
await StartThreadAsync();
var isCorrect = (value == "valid");
}
}
The ValueIsCorrectAsync method works correctly as the Task2 method sets the value field.
The ValueIsNotCorrectAsync method does not work correctly as the await Task.Run in the Task1Async method interferes with the Thread. The StartThreadAsync method returns before the Task2 method sets the value field.
The only difference between the two methods, is the value of awaitRunTask.
How should I change my code such that the value field is set correctly when awaitRunTask = true?
EDIT3
If the await Task.Delay(1000); is commented out in the TestAsync method, the code works for both awaitRunTask = true and awaitRunTask = false;
Can someone please explain to me why? I need to know why because the TestAsync method needs to be able to run asynchronous code.
Why is this?
As I explain on my blog, await here is actually returning to its caller. So the Task1 method returns an incomplete task to its caller, presumably the thread's main method, which presumably is async void. When the thread's main method returns (due to it's await), the thread exits.
The core of the problem is that the Thread type doesn't understand or work naturally with asynchronous code. Thread is really a very low-level building block at this point and is best avoided in modern code. There are very few scenarios where it can't be replaced with Task.Run.
if I want to await a Task.Run on a Thread, is there a way to do this?
The easiest solution is to get rid of the legacy thread completely; replace it with Task.Run.
Otherwise, you need the thread to block. If the continuations can run on thread pool threads, then you can just block directly (e.g., GetAwaiter().GetResult()). If the continuations need to run on that thread, then use AsyncContext from my AsyncEx library.
Here's a minimal version of your sample code:
async Task Main()
{
var te = new ThreadExample();
await te.StartThreadAsync(false);
await te.StartThreadAsync(true);
}
public class ThreadExample
{
public string value;
public async Task StartThreadAsync(bool awaitRunTask)
{
value = "not valid";
var thread = new Thread(() => Task1Async(awaitRunTask));
thread.Start();
thread.Join();
var isCorrect = (value == "valid");
Console.WriteLine(isCorrect);
}
private async Task Task1Async(bool awaitRunTask)
{
if (awaitRunTask)
{
await Task.Run(async () => await Task.Delay(1000));
}
value = "valid";
}
}
This outputs:
True
False
The thread that enters Task1Async executes the line value = "valid" when awaitRunTask == false, but when it's true it hits the await Task.Run and, because of the async state machine, the thread returns to the caller at this point and executes the thread.Join().
Effectively you've created an extreme race condition.
I am writing a wrapper function that executes an arbitrary number of async tasks and will provide retry and error handling policy. I'm having an issue awaiting the result of the async tasks.
The method call looks like this:
Execute(async () => await someAsyncFunction(someValue), async () await someOtherFunction(someValue))
My method implementation looks like this:
void Execute<T1, T2>(Func<T1> fn1, Func<T2> fn2, ... /* overloads for up to 6 functions */)
{
fn1();
fn2();
/* ... */
}
I've not yet applied the error handling and retry policy, but from debugging I've noticed that stepping over fn1 or fn2 is immediate, even when I put a large delay in, for example:
async Task someAsyncFunction(object value)
{
await Task.Delay(10000);
//...
}
Is it possible to achieve what I want with async methods?
An async "action" is actually a function that returns a Task, so it'll be a Func<Task>. You can create a collection of tasks and then await them all with Task.WhenAll. You can supply a flexible number of arguments using the params keyword.
Note also that Execute() must itself be async in order to make async calls.
public class Program
{
static async Task Execute(params Func<Task>[] actions)
{
var tasks = actions.Select( action => action() );
await Task.WhenAll(tasks);
}
public static async Task MainAsync()
{
await Execute
(
async () =>
{
await Task.Delay(3000);
Console.WriteLine("Function 1 done");
}
,
async () =>
{
await Task.Delay(3000);
Console.WriteLine("Function 2 done");
}
);
}
public static void Main()
{
MainAsync().GetAwaiter().GetResult();
}
}
Output:
Function 2 done
Function 1 done
Example code on DotNetFiddle
I'm curious about how the flow of async works across the stack. When reading about async in C#, you will continually read some version of the following:
If the task we are awaiting has not yet completed then sign up the
rest of this method as the continuation of that task, and then return
to your caller immediately; the task will invoke the continuation when
it completes.
It's the return to your caller immediately part that confuses me. In the below example, assuming something calls MethodOneAsync(), execution hits the await in MethodOneAsync. Does it immediately return to the method that called this? If so, how does MethodTwoAsync ever get executed? Or does it continue down the stack until it detects that it's actually blocked (ie. DoDBWorkAsync()) and then yield the thread?
public static async Task MethodOneAsync()
{
DoSomeWork();
await MethodTwoAsync();
}
public static async Task MethodTwoAsync()
{
DoSomeWork();
await MethodThreeAsync();
}
public static async Task MethodThreeAsync()
{
DoSomeWork();
await DoDBWorkAsync();
}
The part before an await in an async method is executed synchronously. That's the case for all async methods.
Let's assume that instead of await DoDBWorkAsync() we have await Task.Delay(1000).
That means MethodOneAsync starts running, executes DoSomeWork and calls MethodTwoAsync which in turn executes DoSomeWork which calls MethodThreeAsync which again executes DoSomeWork.
Then it calls Task.Delay(1000), gets back an uncompleted Task and awaits it.
That await is logically equivalent to adding a continuation and returning the task back to the caller, which is MethodTwoAsync which does the same and return a Task to the caller and so forth and so forth.
That way when the root delay Task completes all the continuations can run one after the other.
If we make your example a bit more complicated:
public static async Task MethodOneAsync()
{
DoSomeWorkOne();
await MethodTwoAsync();
DoMoreWorkOne();
}
public static async Task MethodTwoAsync()
{
DoSomeWorkTwo();
await MethodThreeAsync();
DoMoreWorkTwo();
}
public static async Task MethodThreeAsync()
{
DoSomeWorkThree();
await Task.Delay(1000);
DoMoreWorkThree();
}
It would be logically similar to doing this with continuations:
public static Task MethodOneAsync()
{
DoSomeWorkOne();
DoSomeWorkTwo();
DoSomeWorkThree();
return Task.Delay(1000).
ContinueWith(_ => DoMoreWorkThree()).
ContinueWith(_ => DoMoreWorkTwo()).
ContinueWith(_ => DoMoreWorkOne());
}
First, let me do a different example so my code further down will make sense
public static async Task MethodOneAsync()
{
DoSomeWork1();
await MethodTwoAsync();
DoOtherWork1();
}
public static async Task MethodTwoAsync()
{
DoSomeWork2();
await MethodThreeAsync();
DoOtherWork2();
}
public static async Task MethodThreeAsync()
{
DoSomeWork3();
await DoDBWorkAsync();
DoOtheWork3();
}
All async await does is turn the above code in to something similar to (but even this is a HUGE simplification) this
public static Task MethodOneAsync()
{
DoSomeWork1();
var syncContext = SynchronizationContext.Current ?? new SynchronizationContext();
var resultTask = MethodTwoAsync();
return resultTask.ContinueWith((task) =>
{
syncContext.Post((state) =>
{
SynchronizationContext.SetSynchronizationContext(syncContext);
DoOtherWork1();
}, null);
});
}
public static Task MethodTwoAsync()
{
DoSomeWork2();
var syncContext = SynchronizationContext.Current ?? new SynchronizationContext();
var resultTask = MethodThreeAsync();
return resultTask.ContinueWith((task) =>
{
syncContext.Post((state) =>
{
SynchronizationContext.SetSynchronizationContext(syncContext);
DoOtherWork2();
}, null);
});
}
public static Task MethodThreeAsync()
{
DoSomeWork3();
var syncContext = SynchronizationContext.Current ?? new SynchronizationContext();
var resultTask = DoDbWorkAsync();
return resultTask.ContinueWith((task) =>
{
syncContext.Post((state) =>
{
SynchronizationContext.SetSynchronizationContext(syncContext);
DoOtherWork3();
}, null);
});
}.
Each await just executes the next layer deeper till it is forced to return a Task, once that happens it starts doing continuations on the tasks when they complete and in that continuation it passes in a delegate representing "the rest of the function" to SynchronizationContext.Post( to get the code scheduled to be executed.
How it is scheduled depends on which SynchronizationContext you are in. In WPF and Winforms it queues it to the message pump, for the default and ASP.NET it queues it on a thread pool worker.
It does return after firing the Task for MethodTwoAsync method (or continues execution, if this Task is immediately done), so the inner Task is executing into SynchronizationContext.Current environment.
And after this Task is done, the .NET state machine return the execution to the point right after the MethodTwoAsync firing, and process the rest of the code.
See more information at MSDN article:
I've got some methods that I need to run, one of them should run as a different Thread so I use a Task.Run with lambda, though I want the next method to start just after the Task finishes.
for example I want LastJob() will start after MoreWork() is done:
public void DoSomeWork()
{
Task.Run(() => MoreWork());
LastJob();
}
you can use the async and await key words
link
public async void DoSomeWork()
{
await Task.Run(() => MoreWork());
LastJob();
}
Coy could use the ContinueWith method, like this:
public void DoSomeWork()
{
var task = Task.Run(() => MoreWork());
task.ContinueWith(() => LastJob()) ;
}
According to MSDN:
You can use the AttachedToParent option to express structured task
parallelism, because the parent task implicitly waits for all child
tasks to finish.
So I have this code:
public async Task<int> GetIntAsync()
{
var childTask = Task.Factory.StartNew(async () =>
{
await Task.Delay(1000);
},TaskCreationOptions.AttachedToParent);
return 1;
}
public async Task<ActionResult> Index()
{
var watch = Stopwatch.StartNew();
var task = GetIntAsync();
var result = await task;
var time = watch.ElapsedMilliseconds;
return View();
}
I would like to know why the time is 0 and not 1000.
Code that uses the Task-based Asynchronous Pattern (TAP) does not normally use AttachedToParent. AttachedToParent was part of the design of the Task Parallel Library (TPL). Both the TPL and TAP share the same Task type, but there are many TPL members that should be avoided in TAP code.
In TAP, you can support the notion of "parent" and "child" async methods by having the "parent" async method await the task returned from the "child" async method:
public async Task<int> GetIntAsync()
{
var childTask = Task.Run(() =>
{
...
await Task.Delay(1000);
...
});
...
await childTask;
return 1;
}
AttachedToParent only attaches to tasks that are scheduled. The Task returned by your async method is not scheduled, but rather comes (implicitly) from a TaskCompletionSource
This is a solution that would work for a dynamic number of child tasks.
Using a list would be, in general, naive.
public async Task<int> GetIntAsync()
{
var childTasks = new List<Task>();
while (...)
{
...
childTasks.Add(Task.Run(...));
...
}
await Task.WhenAll(childTasks);
return 1;
}
For example, if the child tasks are short lived and, new ones are created rapidly and unboundedly, then the list would overflow.
Instead, we can use just one task.
public async Task<int> GetIntAsync()
{
var childrenTask = Task.WhenAll();
while (...)
{
...
childrenTask = Task.WhenAll(Task.Run(...), childrenTask);
...
}
await childrenTask;
return 1;
}
Note this is a linked list of tasks which shrinks as soon as a task completes.