Task and asynchronous in Console program - c#

I have just read about special cases in console projects. Could you tell me whether my approach is right. Two jobs there i am not sure whether i should just use await inside Task.Run as i did here, if it is correct can you explain what would be the diffrence if i would delete both awaits from here. Next question what if i would remove .Wait() from WhenAny. Generally is it correct approach in console apps? Forget about proposing async Main so far, let's talk with void.
public class Program
{
public static void Main()
{
//jobs can work in parael not blocking program
var job0 = Task.Run(async () => await new DoThisAsync().Run());
var job1 = Task.Run(async () => await new DoThatAsync().Run());
//Any Independent synchronous work can run meantime jobs
IndependentSynchronousMethod;
//We wait on tasks
Task.WhenAll(job0, job1).Wait();
}
}

Most of this code was not needed
Also if you make your Main async you can do the following
public static async Task Main()
{
var job0 = DoThisAsync();
var job1 = DoThatAsync();
//Any Independent synchronous work can run meantime jobs
IndependentSynchronousMethod;
//We wait on tasks
await Task.WhenAll(job0, job1)
}
To make your Main async
Project -> Build -> Advanced - Language Version >= 7.1
Additional Resources
Task.WhenAll Method
Creates a task that will complete when all of the supplied tasks have
completed.
Can't specify the 'async' modifier on the 'Main' method of a console app
Update
Arie : to make this clear forget about async Main
With no async signature you could do this in a console app.
Task.WhenAll(job0, job1).Wait();
Your code was just wrong and wouldn't compile. However besides that, you were trying to wrap async calls in a task, which is redundant in this case. You are trying to create a task to run a task and its just not needed.
The async signature returns a task by default, Just pass them to WhenAll
If i just call Task.WhenAll(job0, job1) without Wait at the end
program would end before waiting?
Calling an async method returns a task that has already been started. So there is no actual code necessary to force it to run. However, because the task is started something needs to wait for it some how, or in the example the process will end
Task.WhenAll aggregates the tasks, it doesn't start them for you, however if you don't wait for it, or await it, it its self just lets control flow through to the exit of the application

Related

C# async/await with HttpClient GetAsync - non-async calling method

Here is an async/await when calling from a main function which cannot be marked async - the function must run synchronously, but because HttpClient is async, at some point, the await has to make things stop gracefully. I've read a lot about how .Result or .Wait can cause deadlocks, but those are the only versions that actually make the code synchronous.
Here is an example program, roughly following what the code does - note the 4 attempts in the loop - only one of them actually puts data out in the correct order. Is there something fundamentally wrong with this structure/can I not use example #3?
The closest example I can find is here and that is where the calling function can be made async, which this one cannot. I've tried making private static void Process() an async and calling it with Task.Run(async ()=> await Process()); but it still runs out of order. The only thing that consistently works is Wait/Result which can deadlock, particularly with HttpClient from what I've read. Any thoughts?
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace TestAsync
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("1. Calling process at {0:mm.ss.fff}", DateTime.Now);
// Call 1
Process();
Console.WriteLine("1. Calling process at {0:mm.ss.fff}", DateTime.Now);
// Call 2
Process();
Console.ReadKey();
}
private static void Process()
{
Console.WriteLine("2. Calling CallAsyncTest at {0:mm.ss.fff}", DateTime.Now);
for (int i = 1; i < 4; i++)
{
// Try 1 - doesn't work
//CallAsyncTest(i);
// Try 2 - doesn't work
//Task.Run(async () => await CallAsyncTest(i));
// Try 3 - but works not recommended
CallAsyncTest(i).Wait();
// Try 4 - doesn't work
//CallAsyncTest(i).ConfigureAwait(false); ;
}
}
private static async Task CallAsyncTest(int i)
{
Console.WriteLine("{0}. Calling await AsyncTest.Start at {1:mm.ss.fff}", i + 2, DateTime.Now);
var x = await AsyncTest.Start(i);
}
}
public class AsyncTest
{
public static async Task<string> Start(int i)
{
Console.WriteLine("{0}. Calling await Post<string> at {1:mm.ss.fff}", i + 3, DateTime.Now);
return await Post<string>(i);
}
private static async Task<T> Post<T>(int i)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
using (HttpClient httpClient = new HttpClient(new HttpClientHandler()))
{
using (HttpResponseMessage response = await httpClient.GetAsync("https://www.google.com"))
{
using (HttpContent content = response.Content)
{
string responseString = await content.ReadAsStringAsync();
Console.WriteLine("response");
}
}
}
return default(T);
}
}
but those are the only versions that actually make the code synchronous
Exactly, you shouldn't use it for that reason alone. You don't want to lock your main thread while you perform I/O or your application is in the most literal sense trash.
If you don't want to make your entire application async-aware for whatever reason, you can still use proper async patterns. Remember that await is nothing but syntactic sugar around what the Task class already provides you: a way to continue after a task is complete.
So instead of having your process function lock your main thread, you can set up a daisy chain of .ContinueWith() on your four calls (if they're supposed to run in sequence) or on a Task.WhenAll (if they're supposed to run in parallel) and return immediately. The continuation then takes care of updating your UI with the data received (if successful) or error information (if it failed).
the function must run synchronously
As others have noted, the best solutions are to go async all the way. But I'll assume that there's a good reason why this isn't possible.
at some point, the await has to make things stop gracefully.
At some point, your code will have to block on the asynchronous code, yes.
I've read a lot about how .Result or .Wait can cause deadlocks, but those are the only versions that actually make the code synchronous.
Right. Blocking on asynchronous code is the only way to make it synchronous.
It's not actually about Result or Wait per se - it's any kind of blocking. And there are some situations where blocking on asynchronous code will cause deadlocks. Specifically, when all of these conditions are true:
The asynchronous code captures a context. await does capture contexts by default.
The calling code blocks a thread in that context.
The context only allows one thread at a time. E.g., UI thread contexts or legacy ASP.NET request contexts only allow one thread at a time.
Console applications and ASP.NET Core applications do not have a context, so a deadlock will not happen in those scenarios.
The only thing that consistently works is Wait/Result which can deadlock... Any thoughts?
There are some hacks you can choose from to block on asynchronous code.
One of them is just to block directly. This works fine for Console / ASP.NET Core applications (because they don't have a context that would cause the deadlock). I recommend using GetAwaiter().GetResult() in this case to avoid exception wrappers that come when using Result / Wait():
CallAsyncTest(i).GetAwaiter().GetResult();
However, that approach will not work if the application is a UI app or legacy ASP.NET app. In that case, you can push the asynchronous work off to a thread pool thread and block on that. The thread pool thread runs outside the context and so it avoids the deadlock, but this hack means that CallAsyncTest must be able to be run on a thread pool thread - no accessing UI elements or HttpContext.Current or anything else that depends on the context, because the context won't be there:
Task.Run(() => CallAsyncTest(i)).GetAwaiter().GetResult();
There is no solution that works in every scenario. Blocking directly works if there isn't a context (e.g., Console apps). Blocking on Task.Run works if the code can run on an arbitrary thread pool thread. There are a few other hacks available but those two are the most common.
Here's why the other attempts failed.
This one starts the task but doesn't wait at all:
// Try 1 - doesn't work
CallAsyncTest(i);
This one starts the task in a thread pool thread but doesn't wait at all:
// Try 2 - doesn't work
Task.Run(async () => await CallAsyncTest(i));
"Try 4" is exactly the same as "Try 1". The call to ConfigureAwait does nothing because there is no await to configure. So it also just starts the task but doesn't wait at all:
// Try 4 - doesn't work
CallAsyncTest(i).ConfigureAwait(false);
Why not making the Process method async, and then use the normal async await pattern?
The Process signature would be
private static async Task Process()
That would allow you to use await CallAsyncTest(i)
and you would Wait it on the main method, like so:
Process.GetAwaiter().GetResult();
This would be the equivalent to the implementation of async main introduced in C# 7.1
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-7.1/async-main#detailed-design

Use async without await with a function that holds another function that returns void

So I have this WrapperFunction that tries to make a FunctionReturningVoid to be called asynchronously:
public async Task WrapperFunction()
{
this.FunctionReturningVoid("aParameter");
}
This is the function that returns nothing. In some parts of the code (not detailed here) it is called SYNChronously but in the CallerFunction() we want it to be run ASYNChronously.
public void FunctionReturningVoid(string myString)
{
Console.Write(myString);
}
This is the function that has the async implemented and needs to have WrapperFunction do its things without blocking otherStuff().
public async Task CallerFunction()
{
await WrapperFunction():
int regular = otherStuff();
...
}
The IDE is warning me that WrapperFunction is not using await:
This async method lacks 'await' operators and will run synchronously.
Consider using the 'await' operator to await non-blocking API calls,
or 'await Task.Run(...)' to do CPU-bound work on a background thread.
Question: How to use async without using await in WrapperFunction? If I use await it tells me that cannot await void.
It's important to distinguish asynchronous from parallel.
Asynchronous means not blocking the current thread while you're waiting for something to happen. This lets the current thread go do something else while waiting.
Parallel means doing more than one thing at the same time. This requires separate threads for each task.
You cannot call FunctionReturningVoid asynchronously because it is not an asynchronous method. In your example, Console.WriteLine() is written in a way that will block the thread until it completes. You can't change that. But I understand that's just your example for this question. If your actual method is doing some kind of I/O operation, like a network request or writing a file, you could rewrite it to use asynchronous methods. But if it's doing CPU-heavy work, or you just can't rewrite it, then you're stuck with it being synchronous - it will block the current thread while it runs.
However, you can run FunctionReturningVoid in parallel (on another thread) and wait for it asynchronously (so it doesn't block the current thread). This would be wise if this is a desktop application - you don't want to lock up your UI while it runs.
To do that, you can use Task.Run, which will start running code on another thread and return a Task that you can use to know when it completes. That means your WrapperFunction would look like this:
public Task WrapperFunction()
{
return Task.Run(() => this.FunctionReturningVoid("aParameter"));
}
Side point: Notice I removed the async keyword. It's not necessary since you can just pass the Task to the calling method. There is more information about this here.
Microsoft has some well-written articles about Asynchronous programming with async and await that are worth the read.

What's the difference between starting and awaiting a Task?

What's the difference between starting and awaiting? Code below taken from Stephen Cleary's blog (including comments)
public async Task DoOperationsConcurrentlyAsync()
{
Task[] tasks = new Task[3];
tasks[0] = DoOperation0Async();
tasks[1] = DoOperation1Async();
tasks[2] = DoOperation2Async();
// At this point, all three tasks are running at the same time.
// Now, we await them all.
await Task.WhenAll(tasks);
}
I thought that the tasks begin running when you await them ... but the comments in the code seem to imply otherwise.
Also, how can the tasks be running after I just attributed them to an array of type Task. Isn't that just an attribution, by nature not involving action?
A Task returns "hot" (i.e. already started). await asynchronously waits for the Task to complete.
In your example, where you actually do the await will affect whether the tasks are ran one after the other, or all of them at the same time:
await DoOperation0Async(); // start DoOperation0Async, wait for completion, then move on
await DoOperation1Async(); // start DoOperation1Async, wait for completion, then move on
await DoOperation2Async(); // start DoOperation2Async, wait for completion, then move on
As opposed to:
tasks[0] = DoOperation0Async(); // start DoOperation0Async, move on without waiting for completion
tasks[1] = DoOperation1Async(); // start DoOperation1Async, move on without waiting for completion
tasks[2] = DoOperation2Async(); // start DoOperation2Async, move on without waiting for completion
await Task.WhenAll(tasks); // wait for all of them to complete
Update
"doesn't await make an async operation... behave like sync, in this example (and not only)? Because we can't (!) run anything else in parallel with DoOperation0Async() in the first case. By comparison, in the 2nd case DoOperation0Async() and DoOperation1Async() run in parallel (e.g. concurrency,the main benefits of async?)"
This is a big subject and a question worth being asked as it's own thread on SO as it deviates from the original question of the difference between starting and awaiting tasks - therefore I'll keep this answer short, while referring you to other answers where appropriate.
No, awaiting an async operation does not make it behave like sync; what these keywords do is enabling developers to write asynchronous code that resembles a synchronous workflow (see this answer by Eric Lippert for more).
Calling await DoOperation0Async() will not block the thread executing this code flow, whereas a synchronous version of DoOperation0 (or something like DoOperation0Async.Result) will block the thread until the operation is complete.
Think about this in a web context. Let's say a request arrives in a server application. As part of producing a response to that request, you need to do a long-running operation (e.g. query an external API to get some value needed to produce your response). If the execution of this long-running operation was synchronous, the thread executing your request would block as it would have to wait for the long-running operation to complete. On the other hand, if the execution of this long-running operation was asynchronous, the request thread could be freed up so it could do other things (like service other requests) while the long-running operation was still running. Then, when the long-running operation would eventually complete, the request thread (or possibly another thread from the thread pool) could pick up from where it left off (as the long-running operation would be complete and it's result would now be available) and do whatever work was left to produce the response.
The server application example also addresses the second part of your question about the main benefits of async - async/await is all about freeing up threads.
Isn't that just an attribution, by nature not involving action?
By calling the async method you execute the code within. Usually down the chain one method will create a Task and return it either by using return or by awaiting.
Starting a Task
You can start a Task by using Task.Run(...). This schedules some work on the Task Thread Pool.
Awaiting a Task
To get a Task you usually call some (async) Method that returns a Task. An async method behaves like a regular method until you await (or use Task.Run() ). Note that if you await down a chain of methods and the "final" method only does a Thread.Sleep() or synchronous operation - then you will block the initial calling thread, because no method ever used the Task's Thread Pool.
You can do some actual asynchronous operation in many ways:
using Task.Run
using Task.Delay
using Task.Yield
call a library that offers asynchronous operations
These are the ones that come to my mind, there are probably more.
By example
Let's assume that Thread ID 1 is the main thread where you are calling MethodA() from. Thread IDs 5 and up are Threads to run Tasks on (System.Threading.Tasks provides a default Scheduler for that).
public async Task MethodA()
{
// Thread ID 1, 0s passed total
var a = MethodB(); // takes 1s
// Thread ID 1, 1s passed total
await Task.WhenAll(a); // takes 2s
// Thread ID 5, 3s passed total
// When the method returns, the SynchronizationContext
// can change the Thread - see below
}
public async Task MethodB()
{
// Thread ID 1, 0s passed total
Thread.Sleep(1000); // simulate blocking operation for 1s
// Thread ID 1, 1s passed total
// the await makes MethodB return a Task to MethodA
// this task is run on the Task ThreadPool
await Task.Delay(2000); // simulate async call for 2s
// Thread ID 2 (Task's pool Thread), 3s passed total
}
We can see that MethodA was blocked on the MethodB until we hit an await statement.
Await, SynchronizationContext, and Console Apps
You should be aware of one feature of Tasks. They make sure to invoke back to a SynchronizationContext if one is present (basically non-console apps). You can easily run into a deadlock when using .Result or .Wait() on a Task if the called code does not take measures. See https://blogs.msdn.microsoft.com/pfxteam/2012/01/20/await-synchronizationcontext-and-console-apps/
async/await as syntactic sugar
await basically just schedules following code to run after the call was completed. Let me illustrate the idea of what is happening behind the scenes.
This is the untransformed code using async/await. The Something method is awaited, so all following code (Bye) will be run after Something completed.
public async Task SomethingAsync()
{
Hello();
await Something();
Bye();
}
To explain this I add a utility class Worker that simply takes some action to run and then notify when done.
public class Worker
{
private Action _action;
public event DoneHandler Done;
// skipping defining DoneHandler delegate
// store the action
public Worker(Action action) => _action = action;
public void Run()
{
// execute the action
_action();
// notify so that following code is run
Done?.Invoke();
}
}
Now our transformed code, not using async/await
public Task SomethingAsync()
{
Hello(); // this remains untouched
// create the worker to run the "awaited" method
var worker = new Worker(() => Something());
// register the rest of our method
worker.Done += () => Bye();
// execute it
worker.Run();
// I left out the part where we return something
// or run the action on a threadpool to keep it simple
}
Here's the short answer:
To answer this you just need to understand what the async / await keywords do.
We know a single thread can only do one thing at a time and we also know that a single thread bounces all over the application to various method calls and events, ETC. This means that where the thread needs to go next is most likely scheduled or queued up somewhere behind the scenes (it is but I won't explain that part here.) When a thread calls a method, that method is ran to completion before any other methods can be ran which is why long running methods are preferred to be dispatched to other threads to prevent the application from freezing. In order to break a single method up into separate queues we need to do some fancy programming OR you can put the async signature on the method. This tells the compiler that at some point the method can be broken up into other methods and placed in a queue to be ran later.
If that makes sense then you're already figuring out what await does... await tells the compiler that this is where the method is going to be broken up and scheduled to run later. This is why you can use the async keyword without the await keyword; although the compiler knows this and warns you. await does all this for you by use of a Task.
How does await use a Task tell the compiler to schedule the rest of the method? When you call await Task the compilers calls the Task.GetAwaiter() method on that Task for you. GetAwaiter() return a TaskAwaiter. The TaskAwaiter implements two interfaces ICriticalNotifyCompletion, INotifyCompletion. Each has one method, UnsafeOnCompleted(Action continuation) and OnCompleted(Action continuation). The compiler then wraps the rest of the method (after the await keyword) and puts it in an Action and then it calls the OnCompleted and UnsafeOnCompleted methods and passes that Action in as a parameter. Now when the Task is complete, if successful it calls OnCompleted and if not it calls UnsafeOnCompleted and it calls those on the same thread context used to start the Task. It uses the ThreadContext to dispatch the thread to the original thread.
Now you can understand that neither async or await execute any Tasks. They simply tell the compiler to use some prewritten code to schedule all of it for you. In fact; you can await a Task that's not running and it will await until the Task is executed and completed or until the application ends.
Knowing this; lets get hacky and understand it deeper by doing what async await does manually.
Using async await
using System;
using System.Threading.Tasks;
namespace Question_Answer_Console_App
{
class Program
{
static void Main(string[] args)
{
Test();
Console.ReadKey();
}
public static async void Test()
{
Console.WriteLine($"Before Task");
await DoWorkAsync();
Console.WriteLine($"After Task");
}
static public Task DoWorkAsync()
{
return Task.Run(() =>
{
Console.WriteLine($"{nameof(DoWorkAsync)} starting...");
Task.Delay(1000).Wait();
Console.WriteLine($"{nameof(DoWorkAsync)} ending...");
});
}
}
}
//OUTPUT
//Before Task
//DoWorkAsync starting...
//DoWorkAsync ending...
//After Task
Doing what the compiler does manually (sort of)
Note: Although this code works it is meant to help you understand async await from a top down point of view. It DOES NOT encompass or execute the same way the compiler does verbatim.
using System;
using System.Threading.Tasks;
namespace Question_Answer_Console_App
{
class Program
{
static void Main(string[] args)
{
Test();
Console.ReadKey();
}
public static void Test()
{
Console.WriteLine($"Before Task");
var task = DoWorkAsync();
var taskAwaiter = task.GetAwaiter();
taskAwaiter.OnCompleted(() => Console.WriteLine($"After Task"));
}
static public Task DoWorkAsync()
{
return Task.Run(() =>
{
Console.WriteLine($"{nameof(DoWorkAsync)} starting...");
Task.Delay(1000).Wait();
Console.WriteLine($"{nameof(DoWorkAsync)} ending...");
});
}
}
}
//OUTPUT
//Before Task
//DoWorkAsync starting...
//DoWorkAsync ending...
//After Task
LESSON SUMMARY:
Note that the method in my example DoWorkAsync() is just a function that returns a Task. In my example the Task is running because in the method I use return Task.Run(() =>…. Using the keyword await does not change that logic. It's exactly the same; await only does what I mentioned above.
If you have any questions just ask and I'll be happy to answer them.
With starting you start a task. That means it might be picked up for execution by whatever Multitasaking system is in place.
With waiting, you wait for one task to actually finish before you continue.
There is no such thing as a Fire and Forget Thread. You always need to come back, to react to exceptions or do somethings with the result of the asynchronous operation (Database Query or WebQuery result, FileSystem operation finished, Dokument send to the nearest printer pool).
You can start and have as many task running in paralell as you want. But sooner or later you will require the results before you can go on.

Understanding the use of Task.Run + Wait() + async + await used in one line

I'm a C# newbie, so I'm struggling to understand some concepts, and I run into a piece of code that I'm not quite understanding:
static void Main(string[] args)
{
Task.Run(async () => { await SomeClass.Initiate(new Configuration()); }).Wait();
while (true) ;
}
As I understand, this runs a task which initiates a method. This method runs, and then, once it finished, it gets into an infinite loop waiting. It feels that either the code doesn't make sense, or that I'm not understanding right.
Thanks
You can break this apart into several parts:
async () => { await SomeClass.Initiate(new Configuration()); }
Is a lambda expression that defines an async method that just awaits another method. This lambda is then passed to Task.Run:
Task.Run(async () => { await SomeClass.Initiate(new Configuration()); })
Task.Run executes its code on a thread pool thread. So, that async lambda will be run on a thread pool thread. Task.Run returns a Task which represents the execution of the async lambda. After calling Task.Run, the code calls Task.Wait:
Task.Run(async () => { await SomeClass.Initiate(new Configuration()); }).Wait();
This will block the main console app until the async lambda is completely finished.
If you want to see how it's broken out further, the following is roughly equivalent:
static async Task AnonymousMethodAsync()
{
await SomeClass.Initiate(new Configuration());
}
static void Main(string[] args)
{
var task = Task.Run(() => AnonymousMethodAsync());
task.Wait();
while (true) ;
}
I wrote a little .NET Fiddle that simply added some Console.WriteLine calls to hopefully help show you the order of execution.
The Task.Run returns a Task that represents an asynchronous operation, (a method that runs asynchronously). It's parameter in this situation is the Func<Task>. Your code has utilized the async and await keywords, as such your call to SomeClass.Initiate is an async lambda.
Queues the specified work to run on the thread pool and returns a proxy for the task returned by function.
All async code should return an awaitable, unless in the rare situation where you're authoring an event handler that needs to start some async calls.
The Task that is returned from the invocation of Task.Run is immediately invoking .Wait().
Waits for the Task to complete execution within a specified time interval.
That call to Task.Run is not needed, you could simply invoke .Wait() on the Task that is returned from the SomeClass.Initiate method.
As for the infinite loop, a console application exits immediately -- you could simply do the Console.ReadLine and wait for the user to hit the Enter key for example.
Most likely SomeClass.Initiate is synchronous method marked async for no reason. Than someone tried to make it really run asynchronously and added Task.Run to run it on separate thread. But since it is console application - added .Wait() to wait for the operation to finish.
And while (true) ; is there because when running in VS console app closes without trace when it is done, more obvious way - add Console.ReadLine() call. while(true) is not realated to async portion at all as code will not leave .Wait() call before operation is done.
Another possibility is author was experimenting with async and did not have .Wait() or .Result - thus while(true) would give chance for operation to finish.
See async at console app in C#? for proper way to run async code in console app (just .Wait() or .Result)

async Task method that controls the scheduler it runs on

The typical way of writing an async Task method is as follows:
public async Task<int> LongCalculationAsync(int arg)
{
int res = doSomeLongCalculation();
res += await CallSomeOtherTaskAsync();
res ++;
return res;
}
When written like this, the first part (before the await) is performed synchronously, and then another Task is created and started on perhaps another thread, which is then continued by a task that contains the last 2 lines and is run on the original context.
The problem is that the synchronous part is performed on whichever scheduler the caller runs on. But my problem is that I know that I want the task returned to run using a specific scheduler, even if the method is called from the UI thread.
Is there a way for the async method itself to decide on the context?
Use Task.Factory.StartNew to push work to any scheduler you want. For the default thread-pool use Task.Run. It's quite easy:
await Task.Factory.StartNew(() => doSomeLongCalculation(), ...)

Categories

Resources