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
Related
ok. I made a simple console app to figure out how to make all this work. Once I have the basic outline working, then I'll apply it to the real application.
The idea is that we have a lot of database calls to execute that we know are going to take a long time. We do NOT want to (or have to) wait for one database call to be completed before we make the next. They can all run at the same time.
But, before making all of the calls, we need to perform a "starting" task. And when all of the calls are complete, we need to perform a "finished" task.
Here's where I'm at now:
static void Main(string[] args)
{
Console.WriteLine("starting");
PrintAsync().Wait();
Console.WriteLine("ending"); // Must not fire until all tasks are finished
Console.Read();
}
// Missing an "await", I know. But what do I await for?
static async Task PrintAsync()
{
Task.Run(() => PrintOne());
Task.Run(() => PrintTwo());
}
static void PrintOne()
{
Console.WriteLine("one - start");
Thread.Sleep(3000);
Console.WriteLine("one - finish");
}
static void PrintTwo()
{
Console.WriteLine("two - start");
Thread.Sleep(3000);
Console.WriteLine("two - finish");
}
But no matter what I try, Ending always gets printed too early:
starting
ending
one - start
two - start
one - finish
two - finish
What IS working right is that PrintTwo() starts before PrintOne() is done. But how do I properly wait for PrintAsync() to finish before doing anything else?
you need to await the ending of the inner tasks:
static async Task PrintAsync()
{
await Task.WhenAll(Task.Run(() => PrintOne()), Task.Run(() => PrintTwo()));
}
explanation: async Task denotes an awaitable method. Inside this method you can also await Tasks. If you don't do this then it will simply let the tasks loose which will run on their own. Task.Run returns a Task which can be awaited. If you want both tasks to run in parallel you can use the tasks from the retur values and use them in the awaitable method Task.WhenAll
EDIT: Actually Visual Studio would mark this code with a green curvy line. When hoovering with the mouse over it you get a warning:
CS4014
This should explain why "ending" is printed before the tasks have finished
EDIT 2:
If you have a collection of parameters that you want to iterate and call an async method to pass the parameter in, you can also do it with a select statement in 1 line:
static async Task DatabaseCallsAsync()
{
// List of input parameters
List<int> inputParameters = new List<int> {1,2,3,4,5};
await Task.WhenAll(inputParameters.Select(x => DatabaseCallAsync($"Task {x}")));
}
static async Task DatabaseCallAsync(string taskName)
{
Console.WriteLine($"{taskName}: start");
await Task.Delay(3000);
Console.WriteLine($"{taskName}: finish");
}
The last part is similar to a previous answer
OP here. I'm going to leave the answer by Mong Zhu marked as correct, as it lead me to the solution. But I also want to share the final result here, which includes excellent feedback in the comments from juharr. Here's what I came up with:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("starting");
DatabaseCallsAsync().Wait();
Console.WriteLine("ending"); // Must not fire until all database calls are complete.
Console.Read();
}
static async Task DatabaseCallsAsync()
{
// This is one way to do it...
var tasks = new List<Task>();
for (int i = 0; i < 3; i++)
{
tasks.Add(DatabaseCallAsync($"Task {i}"));
}
await Task.WhenAll(tasks.ToArray());
// This is another. Same result...
List<int> inputParameters = new List<int> { 1, 2, 3, 4, 5 };
await Task.WhenAll(inputParameters.Select(x => DatabaseCallAsync($"Task {x}")));
}
static async Task DatabaseCallAsync(string taskName)
{
Console.WriteLine($"{taskName}: start");
await Task.Delay(3000);
Console.WriteLine($"{taskName}: finish");
}
}
Here's the result:
starting
Task 0: start
Task 1: start
Task 2: start
Task 2: finish
Task 0: finish
Task 1: finish
ending
I have four methods.
Main: only calls the preform method
Working: displays "please wait for the user"
Taking Time: A program that takes time to execute.
Preform: Calls the taking time and working methods asynchronously.
The following is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncObservation
{
class Program
{
static void Main(string[] args)
{
preform();
}
public static async Task Working()
{
Console.WriteLine("Please wait, the program is running");
}
public static async Task Takingtime()
{
Console.WriteLine("This Program started");
Thread.Sleep(1000);
Console.WriteLine("The Program finished");
}
public static async void preform()
{
Task timer = Takingtime();
Task wait = Working();
}
}
}
In the end: I need to display
This program started.
Please wait, the program is running
The program ended.
I see several problems in your program.
Although Preform is neither async nor an event handler, it does not return a Task
The tasks started in Preform are not awaited for before you finish Preform. Hence you never know when they are finished, nor what the results are (exception?). You could even end your program before they are finished
After you start a Task it is not guaranteed when it will run. You can only be sure that statements are already executed if you await for the Task.
Using async-await is a method to make sure that your thread looks around to see if it can do useful stuff instead of waiting idly if it has to wait for something. Thread.Sleep is a busy wait. If you want to look around to see if you can do something else use await Task.Delay(TimeSpan.FromSeconds(1)) instead.
In your case, you can't be sure that any Console line has been written until you await the procedure that should write your line. If you start your second Task before awaiting the first, you don't know how far the first task already proceeded, and thus you don't know for sure that the text already has been written to the Console.
C# 7.1 introduced async Task Main(), so you could use that instead of the traditional void Main. It saves you from catching and interpreting the AggregateException that is thrown by the Task you start to make your process async.
If you don't want to use the async Main, you can of course use Task.Run to call an async function:
static void Main(string[] args)
{
try
{
var preformTask = Task.Run( () => Preform() );
DoSomethingElse(); // if needed
preformTask.Wait(); // wait for preformTask to finish
Console.WriteLine("Task completed; press any key to finish");
Console.ReadKey();
}
catch (Exception exc) // inclusive ggregateException if one of your Task fails
{
ProcessException(exc)
}
}
static async Task preform()
{
// To be certain that the Console Line has been written: await
await Takingtime();
// if here, you are certain that the Line has been written,
// or course you have lost parallel processing
await Working();
}
For completeness: the other functions
public static async Task Working()
{
Console.WriteLine("Please wait, the program is running");
// either return a completed Task, or await for it (there is a difference!
await Task.CompletedTask;
// or:
return Task.CompletedTask; // do not declare async in this case
}
public static async Task Takingtime()
{
Console.WriteLine("This Program started");
//Use Task.Delay instead of Sleep
await Task.Delay(TimeSpan.FromSeconds(1); // improved readability
Console.WriteLine("The Program finished");
}
Because of the awaits in Preform you are certain that the text has been written. However, you've lost some parallellism.
If you really want those procedures to execute at the same time, you can't be certain about when text will be written. If that is important, then split the Parts that should be run first (write Console) from the parts that should run in parallel (Task.Delay)
static async Task preform()
{
// Do the things that should be done before parallel tasks are run
await DoThisFirst();
// start the Tasks that can work parallel: not sure what statements are executed first
var taskA = DoTaskA();
var taskB = DoTaskB();
// if here, you are free to do something else
// can't be sure about the status of taskA nor taskB
DoSomethingElse();
// if you want to do something after you know that the tasks have completed:
// await the tasks here:
await Task.When (new Task[] {taskA, taskB});
// if here, you are certain that all parallel tasks have completed successfully
// if desired fetch the return values of the Tasks:
var returnValueA = taskA.Result;
var returnValueB = taskB.Result;
// do all async things of which you needed to be certain that both tasks finished
// for example:
await ProcessResults(returnValueA, returnValueB);
}
In a console app it is OK to use a .Wait() call in an void Main method.
In some contexts where there is synchronisation necessary .Wait() can cause deadlocks (ASP.NET has a request to synchronise on or XAML/WinForms which have a UI thread), but there is nothing to synchronise on here.
static void Main()
{
preform.Wait()
}
This will wait for the async work to complete synchronously. You need the method to run synchronously so that it does not return early. If you use async void and await the method will return immediately and exit the method, await does not work in a Main method.
I would also suggest using await Task.Delay(1000); rather than Thread.Sleep(1000); as this is the canonical async way to idle.
For your code example:
class Program
{
static void Main(string[] args)
{
preform().Wait();
Console.ReadLine();
}
public static async Task Working()
{
Console.WriteLine("Please wait, the program is running");
}
public static async Task Takingtime()
{
Console.WriteLine("This Program started");
await Task.Delay(1000);
Console.WriteLine("The Program finished");
}
public static Task preform()
{
return Task.WhenAll(
Takingtime(),
Working());
}
}
Use Stephen Cleary's Nito.AsyncEx library (available via Nuget) to provide an asynchronous context for a console application. See here for more details.
Your application can then be written as ...
class Program
{
static int Main(string[] args)
{
try
{
Console.WriteLine("The application has started");
AsyncContext.Run(() => LongRunningTaskAsync(args));
Console.WriteLine("The application has finished");
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
return -1;
}
}
static async Task LongRunningTaskAsync(string[] args)
{
Console.WriteLine("The long running task has started");
// use Task.Delay() rather than Thread.Sleep() to avoid blocking the application
await Task.Delay(TimeSpan.FromSeconds(10)).ConfigureAwait(false);
Console.WriteLine("The long running task has finished");
}
}
Use preform().Wait() in the constructor. So the call is awaited. Then use await Takingtime() and await Working() in the preform method.
And you have to change the return type to Task.
I am rather new to task based programming and trying to determine how to return a task and verify that it has been started. The code that I got to work was not what I was expecting. The console application is as follows:
public static void Main(string[] args)
{
var mySimple = new Simple();
var cts = new CancellationTokenSource();
var task = mySimple.RunSomethingAsync(cts.Token);
while (task.Status != TaskStatus.RanToCompletion)
{
Console.WriteLine("Starting...");
Thread.Sleep(100);
}
Console.WriteLine("It is started");
Console.ReadKey();
cts.Cancel();
}
public class Simple
{
public async void RunSomething(CancellationToken token)
{
var count = 0;
while (true)
{
if (token.IsCancellationRequested)
{
break;
}
Console.WriteLine(count++);
await Task.Delay(TimeSpan.FromMilliseconds(1000), token).ContinueWith(task => { });
}
}
public Task RunSomethingAsync(CancellationToken token)
{
return Task.Run(() => this.RunSomething(token));
}
}
The output is:
Starting...
0
It is started
1
2
3
4
Why is the task that is being returned have a status as TaskStatus.RanToCompletion compared to TaskStatus.Running as we see that the while loop is still executing? Am I checking the status of the task of putting the RunSomething task on the threadpool rather than the RunSomething task itself?
RunSomething is an async void method, meaning it exposes no means of the caller ever determining when it finishes, they can only ever start the operation and then have no idea what happens next. You then wrap a call to it inside of Task.Run, this is schedluing a thread pool thread to start RunSomething. It will then complete as soon as it has finished starting that Task.
If RunSomething actually returned a Task, then the caller would be able to determine when it actually finished, and if you waited on it it wouldn't actually indicate that it was done until that asynchronous operation was actually finished (there would be no reason to use Task.Run to start it in another thead, you'd be better off just calling it directly and not wasting the effort of moving that to a thread pool thread).
Never use async void (https://msdn.microsoft.com/en-us/magazine/jj991977.aspx)
instead you should use async Task
If you need to call an async method from a non-async (such as from a static void main) you should do something like this:
mySimple.RunSomethingAsync(cts.Token).GetAwaiter().GetResult();
That will effectively make the method a synchronous call.
You can use async void, but only for events.
I have a C# console application that needs to call a function immediately when the application begins running, in this example ExecuteForLoop(); .
This is how my C# console application starts running:
static void Main()
{
ExecuteForLoop();
Console.Write("Test");
}
the function ExecuteForLoop() in this example does this:
ExecuteForLoop()
{
int example = 0;
for(;;)
{
example++;
}
}
The problem is that if I call the ExecuteForLoop() function the Console.Write("Test"); function will not execute immediately. "Test" will ONLY be outputted to my console once the for(;;) loop within ExecuteForLoop() stops looping.
How can I call ExecuteForLoop() and continue executing code so the function Console.Write("Test"); will be outputted to my C# console application while the for(;;) loop within the ExecuteForLoop() function is still running?
You should almost never use Thread directly.
Use Tasks instead. They are a higher-level abstraction and are much easier to work with than threads.
A simple example:
var backgroundTask = Task.Run(() =>
{
Console.WriteLine("Background task started");
while (true)
{
//do something
}
});
Console.WriteLine("Back in main");
Console.ReadKey();
Another one, cancelling the task after a key is pressed and returning a result:
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
var backgroundTask = Task.Run(() =>
{
Console.WriteLine("Background task started");
long count = 0;
while (!token.IsCancellationRequested)
{
count++;
}
Console.WriteLine("Background task cancelled");
return count;
}, token);
Console.WriteLine("Back in main");
Console.ReadKey();
tokenSource.Cancel();
Console.WriteLine("Counter: {0}", backgroundTask.Result);
Console.ReadKey();
A great resource to learn more about tasks is Stephen Cleary's blog.
Create a Thread and run your logic inside
static void Main()
{
Thread t = new Thread (ExecuteForLoop); // Kick off a new thread
t.Start();
Console.Write("Test");
t.Join(); // wait for thread to exit.
}
I recommend reading Albahari articles/blog on threading, it is very detailed.
Use multi-threading:
static void Main()
{
var t = new Thread(() => ExecuteForLoop());
t.Start();
Console.Write("Test");
t.Join() // See this answer : http://stackoverflow.com/a/14131739/4546874
}
Also, that might not exactly be what you want. Are you sure you need an infinite for-loop in the method? If not, see the syntax for a for-loop and set an exit condition accordingly.
"Test" is not printed because in the previous line you call the ExecuteForLoop() method, in which the program runs into an infinite loop. Since, both statements are in the same thread, the latter cannot be executed unless the previous is, which of course is impossible.
So I'm still trying to understand the async/await pattern, but I'm also trying to achieve the following behavior:
A method A calls method B which runs a number of processes. Some of those processes can be run on separate threads while other things are being processed so that their return values will be available closer to when they are needed. Method B needs to not return control to the caller until all of these processes are completed.
Here is the test code that I am working with:
static void Main(string[] args)
{
CallProc();
Console.WriteLine("Program finished");
Console.ReadKey();
}
public static async Task CallProc()
{
var two = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(5000, "two"));
var one = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(500, "one"));
var three = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(1500, "three"));
// some process happens here
var oneMessage = await one; // waits until one finishes and then snags it's value
Console.WriteLine("Got message {0}", oneMessage);
// some more stuff happens here
var twoMessage = await two; // waits until two is finished and then snags it's value
Console.WriteLine(twoMessage);
// TODO: need to make sure that everything is completed before returning control to caller
}
public static string SomeSynchronousProcessIDontOwn(int delayTime, string message, bool delay = true)
{
Console.WriteLine("Starting \"{0}\"", message);
if(delay) Thread.Sleep(delayTime);
return string.Format("Finished \"{0}\"", message);
}
Right now, what is happening is that everything words as I expected except that the method is returning before everything is finished, so the output shows "Program finished" while "two" is still running.
How do I write this so that CallProc() can execute those tasks asynchronously but delay returning until everything has been completed. In other words, CallProc() needs to run some tasks asynchronously, but CallProc() itself needs to be called synchronously.
The idea of an asynchronous method, which is what you've written is that it will return control (approximately) immediately and the task that it returns will be marked as completed when the operation that it conceptually represents finishes.
This means that your program should either be looking at the resulting task to see when it finishes, or that you don't want an asynchronous method in the first place, and you should re-write CallProc synchronously rather than asynchronously.
To make CallProc synchronous simply remove async (and adjust the return type accordingly), and wait on each task instead of using await.
If CallProc really should be asynchronous then the caller should be adding a continuation (or using await) to perform an action when the task is completed, rather than when the method returns.
Instead of awaiting each task individually why not just await all of them using WhenAll
public static async Task CallProc()
{
var two = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(5000, "two"));
var one = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(500, "one"));
var three = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(1500, "three"));
// run synchronous tasks
await Task.WhenAll(one, two, three);
}
If you would prefer to have CallProc block (i.e. not return until all tasks have finished) then remove the async declaration and use Task.WaitAll instead.
public static void CallProc()
{
// start tasks
Task.WaitAll(one, two, three);
}
One way to do this is to simply call Wait() on the result of CallProc. This will essentially wait for the task returned by CallProc to finish before it continues. Calling Wait in a GUI app can cause a deadlock but for a console app it is fine.
static void Main(string[] args)
{
CallProc().Wait();
Console.WriteLine("Program finished");
Console.ReadKey();
}
That will ensure that "Program finished" is printed after task two is finished.