How to await for one task on two different threads? - c#

Can I await on a Task that was created on a different thread? For example:
...
CurrentIteration = Execute(); // returns Task
await CurrentIteration;
...
And then, on another thread:
...
await CurrentIteration;
...
Will the second thread wait for method Execute to finish executing?
If it will, will I be able to re-use CurrentIteration for the same purpose in the second thread, given that I re-run
CurrentIteration = Execute(); // returns Task
await CurrentIteration;
On the first thread?
I tried this code:
public class Program
{
public static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}
public static async Task MainAsync(string[] args)
{
var instance = new SomeClass();
var task = instance.Execute();
Console.WriteLine("thread 1 waiting...");
Task.Run(async () =>
{
Console.WriteLine("thread 2 started... waiting...");
await task;
Console.WriteLine("thread 2 ended!!!!!");
});
await task;
Console.WriteLine("thread 1 done!!");
Console.ReadKey();
}
}
public class SomeClass
{
public async Task Execute()
{
await Task.Delay(4000);
}
}
But it prints
thread 1 waiting...
thread 2 started... waiting...
then
thread 1 done!!
but never thread 2 ended!!!!!. Why is that? How can I achieve that? Thanks!

You can await on a task from multiple threads. You were actually really close to get that to work, as #Rob said, you just needed to await the second thread.
consider this:
public static async Task MainAsync(string[] args)
{
var instance = new SomeClass();
var task = instance.Execute();
Console.WriteLine("thread 1 waiting...");
var secondTask = Task.Run(async () =>
{
Console.WriteLine("thread 2 started... waiting...");
await task;
Console.WriteLine("thread 2 ended!!!!!");
});
await task;
await secondTask;
Console.WriteLine("thread 1 done!!");
Console.ReadKey();
}
Add the wait on your second thread after you finish waiting for the task.
The reason you didn't see the indication is because the console got stuck on the ReadKey method, and couldn't write anything until it's finished. If you would've pressed Enter, you can see the "thread 2 ended!!!!!" line for a second before the app closes.

Related

Do something periodically while waiting for result of an GetAsync

I want to start an GetAsync or PostAsync and then in a loop do something and check for results.
req1 = client.GetAsync(url_1); // a time consuming request
do
{
//do something here
var req2= await client.GetAsync(url_2);
var result2 = await req2.Content.ReadAsStringAsync();
} while (!IsResultReady(req1)); // check if url_1 job is done and stop the loop
var result1 = await req1.Content.ReadAsStringAsync();
this example should give you what you need
async Task Main()
{
var mainTask = MyLongRunningTask();
// mainTask is already started without await
do
{
await DoSomethingElse();
} while (!mainTask.IsCompleted);
}
public async Task MyLongRunningTask()
{
Console.WriteLine("Long Running Task Started");
await Task.Delay(3000); // simulating client.GetAsync(url_1)
Console.WriteLine("Long Running Task Finished");
}
async Task DoSomethingElse()
{
Console.WriteLine("doing some other tasks");
await Task.Delay(1000);
}
output:
Long Running Task Started
doing some other tasks
doing some other tasks
doing some other tasks
Long Running Task Finished

How to implement tasks with two awaiting points, using async/await

I have some asynchronous operations that consist of two distinct stages. Initially I want to await them until the completion of their first stage, and later await them until their final completion. Here is a simplified version of these operations:
async Task<string> TwoStagesAsync()
{
Console.WriteLine($"Stage 1 Started");
await Task.Delay(1000); // Simulate an I/O operation
bool resultOfStage1 = true;
Console.WriteLine($"Stage 1 Finished");
if (!resultOfStage1) return null;
/* Stage separator */
Console.WriteLine($"Stage 2 Started");
await Task.Delay(1000); // Simulate an I/O operation
Console.WriteLine($"Stage 2 Finished");
return "Hello!";
}
To achieve this requirement I had the idea of representing these two-stage operations as nested tasks: Task<Task<string>>. This would allow me to await initially the outer task, and later await the result of the outer task, which would be the inner task. This is my currently best attempt to implement this idea:
async Task<Task<string>> TwoStagesNestedAsync_A() // Problematic
{
Console.WriteLine($"Stage 1 Started");
await Task.Delay(1000); // Simulate an I/O operation
bool resultOfStage1 = true;
Console.WriteLine($"Stage 1 Finished");
if (!resultOfStage1) return Task.FromResult((string)null);
/* Stage separator */
return Task.Run(async () =>
{
Console.WriteLine($"Stage 2 Started");
await Task.Delay(1000); // Simulate an I/O operation
Console.WriteLine($"Stage 2 Finished");
return "Hello!";
});
}
What I like to this solution is that it works and it is quite readable, since it doesn't require any special synchronization primitives like SemaphoreSlim or TaskCompletionSource. What I don't like is that the second stage is executed in the ThreadPool context instead of the initial SynchronizationContext. Is there any way to make it use the current SynchronizationContext from start to finish, without complicating it too much?
I should include one more of my failed attempts. Replacing the Task.Run with a local async function doesn't work, because for some reason the line Console.WriteLine($"Stage 2 Started") is executed as part of the first stage, instead of the second stage.
async Task<Task<string>> TwoStagesNestedAsync_B() // Problematic
{
Console.WriteLine($"Stage 1 Started");
await Task.Delay(1000); // Simulate an I/O operation
bool resultOfStage1 = true;
Console.WriteLine($"Stage 1 Finished");
if (!resultOfStage1) return Task.FromResult((string)null);
return SecondStageAsync();
async Task<string> SecondStageAsync()
{
Console.WriteLine($"Stage 2 Started");
await Task.Delay(1000); // Simulate an I/O operation
Console.WriteLine($"Stage 2 Finished");
return "Hello!";
}
}
Update: Here is an example of consuming an asynchronous operation that consists of two stages:
Task<Task<string>>[] operations = Enumerable.Range(1, 10)
.Select(_ => TwoStagesNestedAsync_A())
.ToArray();
/* Do something else before awaiting Stage 1 */
Task<string>[] innerTasks = await Task.WhenAll(operations);
Console.WriteLine($"Stage 1 is now complete");
/* Do something else before awaiting Stage 2 */
string[] results = await Task.WhenAll(innerTasks);
Console.WriteLine($"Stage 2 is now complete");
I assume you want to execute something when first stage is complete.
You can pass an action as parameter to the function.
public async Task<string> TwoStagesAsync(Func<Task> injectedAction)
{
await ExecuteStageOne();
// Execute without "stopping" second stage
var injectedTask = injectedAction.Invoke();
if (somethingFailed) return null;
/* Stage separator */
await ExecuteStageTwo();
await injectedTask; // Make sure it completes without errors
return "Hello!";
}
After update
Requirements tell us that consumer of the TwoStages method do know that operation has two stages and this consumer want execute some action between every stage.
So we need to expose tasks of every state to the consumer.
If you wrap TwoStages method within a class, you can expose more details for its consumers.
We write code in object-oriented programming language anyway, isn't it ;)
public class TwoStageOperation
{
public TwoStageOperation() { }
public async Task ExecuteFirstStage()
{
Console.WriteLine($"Stage 1 Started");
await Task.Delay(1000);
Console.WriteLine($"Stage 1 Finished");
}
public async Task<string> ExecuteLastStage()
{
Console.WriteLine($"Stage 2 Started");
await Task.Delay(1000);
Console.WriteLine($"Stage 2 Finished");
return "Hello";
}
}
Usage
var operations = Enumerable.Range(1, 10)
.Select(_ => new TwoStageOperation())
.ToArray();
/* Do something else before awaiting Stage 1 */
await Task.WhenAll(operations.Select(op => op.ExecuteFirstStage());
Console.WriteLine($"Stage 1 is now complete");
/* Do something else before awaiting Stage 2 */
string[] results = await Task.WhenAll(operations.Select(op => op.ExecuteLastStage());
Console.WriteLine($"Stage 2 is now complete");
In case operations has different implementations, you can introduce an interface and have different implementations
public interface ITwoStageOperation
{
Task ExecuteFirstStage();
Task<string> ExecuteLastStage();
}
var operations = new ITwoStageOperation[]
{
new LandTwoStageOperation(),
new OceanTwoStageOperation(),
new AirTwoStageOperation(),
};
Alternative approach
Which I think you will prefer more, because you were very close to it :), would be to return a function as result of first stage
public async Task<Func<Task<string>>> TwoStagesAsync()
{
await ExecuteStageOne();
Func<Task<string>> lastStage = async () =>
{
await Task.Delay(1000);
return "Hello";
};
return lastStage;
}
Usage
var firstStages = Enumerable.Range(1, 10)
.Select(_ => TwoStagesAsync())
.ToArray();
/* Do something else before awaiting Stage 1 */
var lastStages = await Task.WhenAll(firstStages);
Console.WriteLine($"Stage 1 is now complete");
/* Do something else before awaiting Stage 2 */
string[] results = await Task.WhenAll(lastStages.Select(s => s.Invoke());
Console.WriteLine($"Stage 2 is now complete");
Try this.
public static async Task<bool> FirstStageAsync() // Problematic
{
Console.WriteLine($"Stage 1 Started");
await Task.Delay(1000); // Simulate an I/O operation
bool resultOfStage1 = true;
Console.WriteLine($"Stage 1 Finished");
return await Task.FromResult(resultOfStage1);
}
public static async Task<string> SecondStageAsync()
{
Console.WriteLine($"Stage 2 Started");
await Task.Delay(1000); // Simulate an I/O operation
Console.WriteLine($"Stage 2 Finished");
return "Hello!";
}
Then you can call it by:
var task = FirstStageAsync().ContinueWith(async d =>
{
if (d.IsCompleted)
{
var resultOfStage1 = await d;
if (resultOfStage1)
{
var task2 = SecondStageAsync();
task2.Wait();
}
}
});
task.Wait();
Is that you want to achieve?
Be careful with deadlock.
Good Luck!

Program exits upon calling await

I have a while-loop that should repeat the program until a certain condition is met. Inside this loop I call an async function, which prints out a message for me. Here is the (cut-short) code:
private void InitializeMessageSystem ( )
{
do
{
// Do stuff
await printMessage ("Hello World!");
Console.ReadKey();
} while (condition != true)
}
And here the function PrintMessage():
private static async Task PrintMessage (string message, int spd = 1)
{
int delay = 50 / spd;
string[] words = message.Split(' ');
int index = 1;
for (int word = 0; word < words.Length; word++)
{
char[] current = words[word].ToCharArray();
if (index + current.Length > Console.WindowWidth)
{
Console.WriteLine();
index = 1;
}
for (int c = 0; c < current.Length; c++)
{
Console.Write(current[c]);
await Task.Delay(delay);
}
Console.Write(" ");
}
}
Edit: Here's the call from the main function:
static void Main (string[] args)
{
InitializeMessageSystem();
Console.ReadKey();
}
Question
Why does my program exit, when I press a key while the function is not yet completed? I thought the program would wait for the Console.ReadKey() until the function PrintMessage() is completed?
Your problem is that await returns the control flow of the program to the caller of the function. Normally execution is continued at that point when the asynchronous task you await finishes.
So control is returned to your main function as you wait for printMessage and main now waits for a key input. As you hit the key main returns to the OS and your process (including all asynchronous tasks) terminates.
Change your InitializeMessageSystem to
private async Task InitializeMessageSystem ( )
and change the code in main to
InitializeMessageSystem().Wait();
to wait until InitializeMessageSystem finishes completely before waiting for the key.
The below code executes without any errors or warnings. But when you execute the code the program exits silently. What you might be expecting is the program waits for the task to complete, asks the user to press any key and exit. What actually happens is after the await statement is executed the control goes back to the invoking step. In our case after the step await task; is executed, before the task completes the control goes back to the invoking step SomeTask(); and the program exits.
class Program
{
static void Main(string[] args)
{
SomeTask();
}
public static async void SomeTask()
{
Task task = Task.Run(() =>
{
System.Threading.Thread.Sleep(20000);
Console.WriteLine("Task Completed!");
});
await task;
Console.WriteLine("Press any key to exit");
Console.ReadLine();
}
}
To fix this, add await to the SomeTask(); call so that the program waits for async SomeTask() to complete. You should also change the return type
of SomeTask() from void to Task.
class Program
{
static void Main(string[] args)
{
await SomeTask();
}
public static async Task SomeTask()
{
Task task = Task.Run(() =>
{
System.Threading.Thread.Sleep(20000);
Console.WriteLine("Task Completed!");
});
await task;
Console.WriteLine("Press any key to exit");
Console.ReadLine();
}
}
The difference between calling a synchronous function and an async function is that when calling the synchronous function you know that when you reach the statement after the call the function is executed completely. When calling an async function, the function is scheduled as a task at the thread pool to be performed when any of the threads in the pool has time for it.
This gives you time to do other things while one of the threads is performing the task. As soon as you need the result you await for the task to be finished.
This works only if your function is also async. If you don't make your function async your can't use async-await. Making your function async and the clients of your function also async is the only way to truly use async-await. Remember: all async functions should return Task instead of void and Task<TResult> instead of TResult. The only exception is the event handler
private async void Button1_Clicked(object sender, ...)
{
var myTask = SlowMultiplierAsync(4, 3);
// while myTask is running you can do other things
// after a while you need the result:
int taskResult = await myTask;
Process(taskResult);
}
private async Task<int> SlowMultiplierAsync(int x, int y)
{
// let's take a nap before multiplying
// do this by awaiting another async function:
await Task.Delay(TimeSpan.FromSeconds(5));
return x * y;
}
If you don't want (or can) make your function async, you can simulate similar behaviour by starting a task using task.Run:
private void InitializeMessageSystem ( ) {
do
{
// Do stuff
var myTask = task.Run( () => printMessage ("Hello World!"));
myTask.Wait();
Console.ReadKey();
} while (condition != true)
Although this will make sure that your function won't end before the task is finished, your function will be a synchronous one for your clients. For instance it won't make your UI responsive.
Eric lippert here on stackoverflow once explained me the difference between asynchronous concurrent. Link to his answer
Suppose you have to make breakfast. Toast some bread and cook some eggs.
Synchronous: start toasting bread. Wait until toasting finished. Start cooking eggs, wait until eggs are cooked.
Asynchronous but not concurrent: start toasting bread, and while the bread is toasting start cooking eggs. While the eggs are cooking yo can do other things, like making tea. After a while you wait until the eggs are cooked and wait until the bread is toasted. This is typically async-await.
Asynchronous and concurrent: hire a cook to toast the bread, hire a cook to cook the eggs and wait until both cooks are finished. Here the toasting and cooking is done by different threads. It is the most expensive method

SemaphoreSlim.WaitAsync continuation code

My understanding of the await keyword was that the code following the await qualified statement is running as the continuation of that statement once it is complete.
Hence the following two versions should produce the same output:
public static Task Run(SemaphoreSlim sem)
{
TraceThreadCount();
return sem.WaitAsync().ContinueWith(t =>
{
TraceThreadCount();
sem.Release();
});
}
public static async Task RunAsync(SemaphoreSlim sem)
{
TraceThreadCount();
await sem.WaitAsync();
TraceThreadCount();
sem.Release();
}
But they do not!
Here is the complete program:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace CDE
{
class Program
{
static void Main(string[] args)
{
try
{
var sem = new SemaphoreSlim(10);
var task = Run(sem);
Trace("About to wait for Run.");
task.Wait();
Trace("--------------------------------------------------");
task = RunAsync(sem);
Trace("About to wait for RunAsync.");
task.Wait();
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
Trace("Press any key ...");
Console.ReadKey();
}
public static Task Run(SemaphoreSlim sem)
{
TraceThreadCount();
return sem.WaitAsync().ContinueWith(t =>
{
TraceThreadCount();
sem.Release();
});
}
public static async Task RunAsync(SemaphoreSlim sem)
{
TraceThreadCount();
await sem.WaitAsync();
TraceThreadCount();
sem.Release();
}
private static void Trace(string fmt, params object[] args)
{
var str = string.Format(fmt, args);
Console.WriteLine("[{0}] {1}", Thread.CurrentThread.ManagedThreadId, str);
}
private static void TraceThreadCount()
{
int workerThreads;
int completionPortThreads;
ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
Trace("Available thread count: worker = {0}, completion port = {1}", workerThreads, completionPortThreads);
}
}
}
Here is the output:
[9] Available thread count: worker = 1023, completion port = 1000
[9] About to wait for Run.
[6] Available thread count: worker = 1021, completion port = 1000
[9] --------------------------------------------------
[9] Available thread count: worker = 1023, completion port = 1000
[9] Available thread count: worker = 1023, completion port = 1000
[9] About to wait for RunAsync.
[9] Press any key ...
What am I missing?
async-await optimizes for when the task you're awaiting on has already completed (which is the case when you have a semaphore set to 10 with only 1 thread using it). In that case the thread just carries on synchronously.
You can see that by adding an actual asynchronous operation to RunAsync and see how it changes the thread pool threads being used (which would be the behavior when your semaphore is empty and the caller actually needs to wait asynchronously):
public static async Task RunAsync(SemaphoreSlim sem)
{
TraceThreadCount();
await Task.Delay(1000);
await sem.WaitAsync();
TraceThreadCount();
sem.Release();
}
You can also make this change to Run and have it execute the continuation synchronously and get the same results as in your RunAsync (thread count wise):
public static Task Run(SemaphoreSlim sem)
{
TraceThreadCount();
return sem.WaitAsync().ContinueWith(t =>
{
TraceThreadCount();
sem.Release();
}, TaskContinuationOptions.ExecuteSynchronously);
}
Output:
[1] Available thread count: worker = 1023, completion port = 1000
[1] Available thread count: worker = 1023, completion port = 1000
[1] About to wait for Run.
[1] --------------------------------------------------
[1] Available thread count: worker = 1023, completion port = 1000
[1] Available thread count: worker = 1023, completion port = 1000
[1] About to wait for RunAsync.
[1] Press any key ...
Important Note: When it's said that async-await acts as a continuation it's more of an analogy. There are several critical difference between these concepts, especially regarding SynchronizationContexts. async-await automagically preserves the current context (unless you specify ConfigureAwait(false)) so you can use it safely in environments where that matters (UI, ASP.Net, etc.). More about synchronization contexts here.
Also, await Task.Delay(1000); may be replaced with await Task.Yield(); to illustrate that the timing is irrelevant and just the fact that the method waits asynchronously matters. Task.Yield() is often useful in unit tests of asynchronous code.
They won't as when you're calling async method, it's starting immediately. So, as long as your semaphore is not locked, WaitAsync() won't even start and there'll be no context switching (it's kind of optimization, same is applied to the canceled tasks), so your async method will be synchronous.
Meanwhile continuation version will actually start continuation on the parallel thread.

How to determine the status of the job Async/Await

i read this guide line from here http://blog.stephencleary.com/2012/02/async-and-await.html
here i got few couple of code but not very clear to me.
1)
public async Task DoOperationsInParallelAsync()
{
Task[] tasks = new Task[3];
tasks[0] = DoOperation0();
tasks[1] = DoOperation1();
tasks[2] = DoOperation2();
// At this point, all three tasks are running in parallel.
// Now, we await them all.
await Task.WhenAll(tasks);
}
in the above we are creating multiple task but suppose when all task will run parallel then DoOperation2() may be finish first and DoOperation0() and at last DoOperation1() complete. if i want to show that message like DoOperation2() is completed in console windows then how could i do this. how could i detect that which task complete when multiple is running.
2) when we run any function with the help of async/await the does it run as background thread or foreground thread.
3)
public async Task<int> GetFirstToRespondAsync()
{
// Call two web services; take the first response.
Task<int>[] tasks = new[] { WebService1(), WebService2() };
// Await for the first one to respond.
Task<int> firstTask = await Task.WhenAny(tasks);
// Return the result.
return await firstTask;
}
i do not understand why the person wrote Await for the first one to respond.
// Await for the first one to respond.
Task firstTask = await Task.WhenAny(tasks);
why first one...why not second one because two task are running here.
please guide me and drive out my confusion. thanks
Because it's a console app, you need to wait for the task to finish. Here's an example of how to return a string from a task:
class WhenAny
{
public static async Task<string> GetFirstToRespondAsync()
{
// Call two web services; take the first response.
Task<string>[] tasks = new[] { Task1(), Task2() };
// Await for the first one to respond.
Task<string> firstTask = await Task.WhenAny(tasks);
// Return the result.
return firstTask.Result;
}
private static async Task<string> Task1()
{
await Task.Delay(3000);
return "Task1";
}
private static async Task<string> Task2()
{
await Task.Delay(1000);
return "Task2";
}
}
Call that from the Main function as follows:
static void Main(string[] args)
{
var t = WhenAny.GetFirstToRespondAsync();
t.ContinueWith((taskName) =>
{
string result = taskName.Result;
Console.WriteLine("Result: " + result);
});
t.Wait();
Console.ReadLine();
}
That should return the task that completes first, and you can access that information from the Task.Result
Awaiting a method does not, in itself, create an additional thread. What it does is create a callback to avoid blocking the current thread (typically this is used to not block the UI thread).
WhenAny returns when the earliest completed operation returns. That doesn't mean the first in the list that you provide. So, the code above will always show 1000, even though it's the second task.
For completeness, here's the same thing with WhenAll:
class WhenAll
{
public static async Task<string[]> WaitForAllAsync()
{
// Call two web services; take the first response.
Task<string>[] tasks = new[] { Task1(), Task2(), Task3() };
// Wait for a tasks
string[] results = await Task.WhenAll(tasks);
// Return the result.
return results;
}
private static async Task<string> Task1()
{
await Task.Delay(3000);
return "Task1";
}
private static async Task<string> Task2()
{
await Task.Delay(1000);
return "Task2";
}
private static async Task<string> Task3()
{
await Task.Delay(5000);
return "Task3";
}
}
And to call it:
static void Main(string[] args)
{
var t = WhenAll.WaitForAllAsync();
t.ContinueWith((task) =>
{
string[] result = task.Result;
foreach(string taskname in result)
{
Console.WriteLine("Result: " + taskname);
}
});
t.Wait();
Console.ReadLine();
}
You can use ContinueWith method for every task that will update the progress.
So...
foreach (var t in tasks)
{
t.ContinueWith(Console.WriteLine("Hey I am done"));
}
1) Pass in a callback function
public async Task DoOperationsInParallelAsync(Action<Task<int>> completed)
{
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
var tasks = new[] { DoOperation0(), DoOperation1(), DoOperation2() };
var completedTasks = tasks.Select(x => x.ContinueWith(completed, uiScheduler)).ToArray();
await Task.WhenAll(completedTasks);
}
private async void Button1_Click(object sender, EventArgs e)
{
await DoOperationsInParallelAsync(t => {
Label1.Text = string.Format("Task finished with {0}", t.Result);
});
}
2) The Task will run on the threadpool unless you specify it as long running or provide a TaskScheduler.
3) When only the first result matters (computation is redundant or time sensitive) such as grabbing stock prices from various providers mirroring similar data.

Categories