C# Async method call all the way to Main - c#

Can someone clarify this example, which of course, is not working:
class Program
{
static void Main(string[] args)//main cant' be async
{
int res = test();//I must put await here
Console.WriteLine("END");
}
public async static Task<int> test()
{ //why can't I make it just: public int test()??
int a1, a2, a3, a4;
a1 = await GetNumber1();
a2 = await GetNumber2();
a3 = await GetNumber3();
a4 = a1 + a2 + a3;
return a4;
}
public static async Task<int> GetNumber1()
{
await Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("GetNumber1");
System.Threading.Thread.Sleep(100);
}
});
return 1;
}
I am trying to "collect" values from GenNumberX methods by using "await". I would like to make method "test" not async somehow. I dont understand why test has to be async when I am using await to get a value. This example makes me to write async on every method where I use async, and when I drill up to Main, I cannot make it async?
How to write real-world example:
public bool ReserveAHolliday()
{
bool hotelOK = await ReserveAHotel();//HTTP async request
bool flightOK = await ReserveFlight();////HTTP async request
bool result = hotelOK && flightOK;
return result;
}
How to make method ReserveAHolliday synchronous?
Am I missing something or don't understand the use of async-await mechanism?

below is a full example. you can run the ReserverAHoliday both Synchronously (bool r = ReserveAHolliday().Result;) and Asynchronously (just call ReserveAHolliday();) from MAIN (depends which line you comment). and you can see the effect ("END" gets printed before / after the reservation is complete).
I prefer the await Task.WhenAll() methods, which is more readable.
also note that it's preferred to use await Task.Delay(100) instead of Thread.sleep inside GetNumber1.
class Program
{
static void Main(string[] args)//main cant' be async
{
//int res = test().Result;//I must put await here
bool r = ReserveAHolliday().Result; //this will run Synchronously.
//ReserveAHolliday(); //this option will run aync : you will see "END" printed before the reservation is complete.
Console.WriteLine("END");
Console.ReadLine();
}
public async static Task<int> test()
{ //why can't I make it just: public int test()??
//becuase you cannot use await in synchronous methods.
int a1, a2, a3, a4;
a1 = await GetNumber1();
a2 = await GetNumber1();
a3 = await GetNumber1();
a4 = a1 + a2 + a3;
return a4;
}
public static async Task<int> GetNumber1()
{
//await Task.Run(() =>
// {
for (int i = 0; i < 10; i++)
{
Console.WriteLine("GetNumber1");
await Task.Delay(100); // from what I read using Task.Delay is preferred to using System.Threading.Thread.Sleep(100);
}
// });
return 1;
}
public async static Task<bool> ReserveAHolliday()
{
//bool hotelOK = await ReserveAHotel();//HTTP async request
//bool flightOK = await ReserveAHotel();////HTTP async request
var t1 = ReserveAHotel("FirstHotel");
var t2 = ReserveAHotel("SecondHotel");
await Task.WhenAll(t1, t2);
bool result = t1.Result && t1.Result;// hotelOK && flightOK;
return result;
}
public static async Task<bool> ReserveAHotel(string name)
{
Console.WriteLine("Reserve A Hotel started for "+ name);
await Task.Delay(3000);
if (name == "FirstHotel")
await Task.Delay(500); //delaying first hotel on purpose.
Console.WriteLine("Reserve A Hotel done for " + name);
return true;
}
}

First of all never use Result it has a bad implementation and you
will end up having deadlocks. Instead use GetAwaiter().GetResult()
If you are using C# 7.0 or below then it's safe to use this pattern:
static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}
private static async Task MainAsync(string[] args)
{
await MyMethod();
await MyOtherMethod();
Console.WriteLine("Done!");
}
private static async Task MyMethod()
{
// do something
await Task.CompletedTask;
}
private static async Task MyOtherMethod()
{
// do something
await Task.CompletedTask;
}
If you are using C# 7.1+ then you can change the main method to be an async one like this:
static async Task Main(string[] args)
{
await MyMethod();
await MyOtherMethod();
Console.WriteLine("Done!");
}
private static async Task MyMethod()
{
// do something
await Task.CompletedTask;
}
private static async Task MyOtherMethod()
{
// do something
await Task.CompletedTask;
}
In .Net core project you can change to C# 7.1 or higher by using this tag:
<LangVersion>7.1</LangVersion>
or
<LangVersion>latest</LangVersion>
The project file will look like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<LangVersion>latest</LangVersion>
</PropertyGroup>
</Project>

Thank you FrankerZ for the right answer!
So my litle example should look something like this:
class Program
{
static void Main(string[] args)
{
var task = test();
task.Wait(); //this stops async behaviour
int result = task.Result;// get return value form method "test"
Console.WriteLine("RESULT IS = " + result);
}
public async static Task<int> test()
{
int a1, a2, a3, a4;
//run all tasks
//all tasks are doing their job "at the same time"
var taskA1 = GetNumber1();
var taskA2 = GetNumber2();
var taskA3 = GetNumber3();
//wait for task results
//here I am collecting results from all tasks
a1 = await taskA1;
a2 = await taskA2;
a3 = await taskA3;
//get value from all task results
a4 = a1 + a2 + a3;
return a4;
}
public static async Task<int> GetNumber1()
{
await Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("GetNumber1");
System.Threading.Thread.Sleep(100);
}
});
return 1;
}
//other methods are ommited because they are the same like GetNumber1
}

In order to use the await keyword inside a method, it has to be async. This was a design decision to make it easier to be backwards compatible.
Main cannot be async as it is the starting point of the program, so you typically need to block somehow to keep the program running. You can do that by blocking on a Task or even by calling Console.ReadLine.
Tasks usually execute on a background thread and background threads do not keep your program running if all foreground threads stop.
I've got an introductory blog post on async-await here

Your async needs to start somewhere, and since your program has a starting point, it's a synchronous method at this point. Most async's start at what we like to call async void's, which are basically fire and forget methods. It starts a task, and doesn't care what it returns. If you need to wait for something in a synchronous method, you can use the .Wait() method on a task, or use .Result to get the result of the task.
For your real world example, if you want to run both tasks at the same time, you would need to do something like this:
public async Task<bool> ReserveAHoliday()
{
//Initialize and start this task
Task<bool> hotelTask = ReserveAHotel();//HTTP async request
//Initialize and start this task
Task<bool> flightTask = ReserveFlight();////HTTP async request
//Await until hotel task is done, and get the bool
bool hotelOK = await hotelTask;
//Await until flight task is done (This might have already finished while the hotel was grabbing, and get the bool
bool flightOK = await flightTask;
bool result = hotelOK && flightOK;
//Return the final result
return result;
}
I highly recommend watching this video. It gives a nice introduction to how Async works, and can jump start you in the wonderful world of Async.

The method ReserveAHolliday cannot be made synchronous if you use the await keyword inside of it.
What could be possible is to simply block till both async methods return their value. I don't recommend it though because it could lead to deadlocks or other unexpected errors.
If you don't have a synchronization context (eg. console application) you can simply write
bool hotelOK = ReserveAHotel().Result;
But I reckon you ultimately want to create a GUI. That is where blocking falls apart. Because UI application (Forms and WPF) do have a context and waiting for asynchronous methods cause deadlocks. Read more here
There are workarounds for this problem, but they are highly dependent on the design of your application.
Edit:
If your library code needs Synchronization Context then blocking will most certainly cause a deadlock.
If you don't need it, it's possible to use ConfigureAwait(false) in your library code and get away with blocking.
What I recommend is: async/await all the way or no async/await at all. There are other possibilities to make your code asynchronous, eg: event based, but like everything in life has pros and cons.
Please read this blog from Stephen Cleary. He explains why blocking async code will deadlock and how you can avoid it.

Related

C# Windows Async Pinging Network - different results each run

I've written a class that asynchronously pings a subnet. It works, however, the number of hosts returned will sometimes change between runs. Some questions:
Am I doing something wrong in the code below?
What can I do to make it work better?
The ScanIPAddressesAsync() method is called like this:
NetworkDiscovery nd = new NetworkDiscovery("192.168.50.");
nd.RaiseIPScanCompleteEvent += HandleScanComplete;
nd.ScanIPAddressesAsync();
namespace BPSTestTool
{
public class IPScanCompleteEvent : EventArgs
{
public List<String> IPList { get; set; }
public IPScanCompleteEvent(List<String> _list)
{
IPList = _list;
}
}
public class NetworkDiscovery
{
private static object m_lockObj = new object();
private List<String> m_ipsFound = new List<string>();
private String m_ipBase = null;
public List<String> IPList
{
get { return m_ipsFound; }
}
public EventHandler<IPScanCompleteEvent> RaiseIPScanCompleteEvent;
public NetworkDiscovery(string ipBase)
{
this.m_ipBase = ipBase;
}
public async void ScanIPAddressesAsync()
{
var tasks = new List<Task>();
m_ipsFound.Clear();
await Task.Run(() => AsyncScan());
return;
}
private async void AsyncScan()
{
List<Task> tasks = new List<Task>();
for (int i = 2; i < 255; i++)
{
String ip = m_ipBase + i.ToString();
if (m_ipsFound.Contains(ip) == false)
{
for (int x = 0; x < 2; x++)
{
Ping p = new Ping();
var task = HandlePingReplyAsync(p, ip);
tasks.Add(task);
}
}
}
await Task.WhenAll(tasks).ContinueWith(t =>
{
OnRaiseIPScanCompleteEvent(new IPScanCompleteEvent(m_ipsFound));
});
}
protected virtual void OnRaiseIPScanCompleteEvent(IPScanCompleteEvent args)
{
RaiseIPScanCompleteEvent?.Invoke(this, args);
}
private async Task HandlePingReplyAsync(Ping ping, String ip)
{
PingReply reply = await ping.SendPingAsync(ip, 1500);
if ( reply != null && reply.Status == System.Net.NetworkInformation.IPStatus.Success)
{
lock (m_lockObj)
{
if (m_ipsFound.Contains(ip) == false)
{
m_ipsFound.Add(ip);
}
}
}
}
}
}
One problem I see is async void. The only reason async void is even allowed is only for event handlers. If it's not an event handler, it's a red flag.
Asynchronous methods always start running synchronously until the first await that acts on an incomplete Task. In your code, that is at await Task.WhenAll(tasks). At that point, AsyncScan returns - before all the tasks have completed. Usually, it would return a Task that will let you know when it's done, but since the method signature is void, it cannot.
So now look at this:
await Task.Run(() => AsyncScan());
When AsyncScan() returns, then the Task returned from Task.Run completes and your code moves on, before all of the pings have finished.
So when you report your results, the number of results will be random, depending on how many happened to finish before you displayed the results.
If you want make sure that all of the pings are done before continuing, then change AsyncScan() to return a Task:
private async Task AsyncScan()
And change the Task.Run to await it:
await Task.Run(async () => await AsyncScan());
However, you could also just get rid of the Task.Run and just have this:
await AsyncScan();
Task.Run runs the code in a separate thread. The only reason to do that is in a UI app where you want to move CPU-heavy computations off of the UI thread. When you're just doing network requests like this, that's not necessary.
On top of that, you're also using async void here:
public async void ScanIPAddressesAsync()
Which means that wherever you call ScanIPAddressesAsync() is unable to wait until everything is done. Change that to async Task and await it too.
This code needs a lot of refactoring and bugs like this in concurrency are hard to pinpoint. My bet is on await Task.Run(() => AsyncScan()); which is wrong because AsyncScan() is async and Task.Run(...) will return before it is complete.
My second guess is m_ipsFound which is called a shared state. This means there might be many threads simultaneously reading and writing on this. List<T> is not a data type for this.
Also as a side point having a return in the last line of a method is not adding to the readability and async void is a prohibited practice. Always use async Task even if you return nothing. You can read more on this very good answer.

not understanding of async await concept [duplicate]

This question already has an answer here:
Async Await Running Synchronously
(1 answer)
Closed 2 years ago.
I do not understand when I read the Microsoft documents about async and await working, as it says
Async methods are intended to be non-blocking operations. An await
expression in an async method doesn’t block the current thread while
the awaited task is running. Instead, the expression signs up the rest
of the method as a continuation and returns control to the caller of
the async method.
so consider my code:
public Form1()
{
InitializeComponent();
AsyncTest();
Test(1);
}
private async void AsyncTest()
{
HttpClient client = new HttpClient();
var ss = TT(2);
var s = await ss;
for (int i = 0; i < 10; i++)
{
//loop
}
}
private async Task<int> TT(int i)
{
while (true)
{
if (i > 1000000000)
break;
i++;
}
return i;
}
}
when ever I call AsyncTest(), it just waits behind TT method as it specified with await key, but what does it mean it return control to the main caller??
it is not been returned to the form1, if TT is an infinite loop it just remains forever.
thanks
It seems to me you are a newbee to async-await. You violate several rules about how to use async-await.
To make a function async do the following:
Declare the function async
Return Task<TResult> instead of TResult; return Task instead of void
ONLY EXCEPTION: event handlers return void instead of Task
there should be one await inside your async function. Your compiler will warn you if you omit this.
Make sure that all async functions that you call are awaited for before you return
Guideline: let async be a suffix to your async functions. This allows you to create a sync and an async function that do the same: void MyTest() and Task MyTestAsync()
Following these rules, you can't call an async function from within a constructor. As you are using Winforms your code could be like this:
public Form1()
{
InitializeComponent();
}
public async void OnButton1_Clicked(object sender, ...)
{ // because this is an event handler the return value is void
// Start the first test and await until ready
await TestAsync();
// Start the second test and await until ready:
int i = await TestAsync(1);
}
If you call an async function you know that somewhere inside this function is an await. If you have meaningful things to do while the inner function is awaiting, do not await yet. Do your useful things after the call and await the returned Task as soon as you need the result:
public async void OnButton2_Clicked(object sender, ...)
{
// Start a test, but don't await yet
var task1 = TestAsync(1);
// if here, function TestAsync is awaiting somewhere
// it is not finished yet, so you can't use the result of it
// But you can do Something else:
DoSomethingElse();
// if here you really need the result of TestAsync, await for it
int i = await task1;
// if here you know that TestAsync is finished, i has the proper return value
}
You don't have to start and await the tasks one by one, you can start several tasks and await for them as soon as you need the results:
public async void OnButton3_Clicked(object sender, ...)
{
// start several tasks. Don't await yet:
var task1 = TestAsync(1);
var task2 = TestAsync(2);
var task3 = TestAsync(3);
DoSomethingElse();
// if here I need the results of all three tasks:
var myTasks = new Task[] {task1, task2, task3};
await Task.WhenAll(myTasks);
}
An article that really helped me understanding async-await is this interview with Eric Lippert, where he compares async-await with a cook making breakfast. If a cook has to wait for the water to boil, he doesn't wait idly, but looks around to see if he can do other things. Search somewhere in the middle for async-await.
Another article that helped me following the guidelines of async-await is Async and Await by the ever so helpful Stephen Cleary

How would this program look in terms of drawing threading on a graph?

In my attempt to understand async-await, I've written a simple program
private static async Task<int> GetIntAsync()
{
Task<int> getInt = GetInt();
DoSomeMoreIndependentWork();
int i = await getInt;
SomeStuffAfterTheAwait();
return i;
}
public static void Main()
{
Task.Run(async () =>
{
Task<int> getIntAsync = GetIntAsync();
DoIndependentWork();
int result = await getIntAsync;
Console.WriteLine(result);
}).Wait();
}
and want to understand it in terms of the graph from here.
Here's what I think is a possible flow of execution if DoIndependentWork and DoSomeMoreIndependentWork take a long time to execute:
|<--Launch GetInt-->||<-- DoSomeMoreIndependentWork-->||<-- DoIndependentWork -->||<-- Wait for GetInt to finish -->||<-- SomeStuffAfterTheAwait -->||<-- Console.WriteLine(result) -->|
|<------ Do GetInt .................................................................... ------>|
Is that correct? If not, what is a better representation of some or all of the possible flows of execution?

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.

Convert TaskCompletionSource to Task.FromResult<TResult>?

I have this simple code which start a method asynchronously. it uses TCS in order to wrap the code with Task.
Task<int> DoWork()
{
var source = new TaskCompletionSource <int>();
Thread.Sleep(220);
source.SetResult(9999999);
return source.Task;
}
void Main()
{
Console.WriteLine(1);
var t1=Task.Factory.StartNew(()=>DoWork());
t1.ContinueWith(_=>Console.WriteLine ("doing something different "));
t1.ContinueWith(_=>Console.WriteLine ("finished , value is ="+_.Result.Result));
Console.WriteLine(2);
Console.ReadLine();
}
output :
1
2
doing somethign different //those last 2 lines can be swapped
finished , value is =9999999
But now , I want to convert it to use Task.FromResult<TResult>.
This is poorly documented , so I wonder , how can I convert my code above to use Task.FroResult instead ?
The easiest way to use FromResult would be to do:
public Task<int> DoWork()
{
return Task.FromResult(99999);
}
But it's an exact functional equivalent of doing:
var tcs = new TaskCompletionSource<int>();
tcs.SetResult(99999);
return tcs.Task;
so it doesn't sleep for 220 ms. For the 'delayed' variant, easiest way would be:
public async Task<int> DoWork()
{
await Task.Delay(220);
return 99999;
}
and this version behaves close enough to the example you provided.
In your code, you return the Task only after the synchronous wait is over, so your code is equivalent to:
Task<int> DoWork()
{
Thread.Sleep(220);
return Task.FromResult(9999999);
}
But if you returned the Task immediately and then blocked some other thread:
Task<int> DoWork()
{
var source = new TaskCompletionSource<int>();
Task.Run(() =>
{
Thread.Sleep(220);
source.SetResult(9999999);
});
return source.Task;
}
(Note: I'm not saying you should do this in real code.)
This code couldn't be simulated by Task.FromResult(), because that always creates an already completed Task.

Categories