Confusion on async and await logic in c#? - c#

i have a great confusion while working with the async and await.
My logic is simple, i have a method which will cause a delay of 15 seconds, like this
public static Task<int> delay(int num)
{
Task.Delay(15000);
return Task.FromResult(num);
}
now i am calling this method like this
public static async void delayAsync(int num)
{
Console.WriteLine(await delay(num)+"time :"+DateTime.Now);
}
static void Main(string[] args)
{
var details = new details();
Console.WriteLine("## start ##");
for (var i = 0; i < 5; i++)
{
Console.WriteLine("counter: "+i);
delayAsync(i);
}
Console.WriteLine("## finished ##");
Console.Read();
}
my desired output is to get the number one by one after the delay of 15 seconds, but i am getting the results all at once without any pause. am i missing something.
I have gone through this blog and couldnt understand a thing

Here are the steps that you need to achieve this:
Await Task.Delay and return num instead of Task.
public static async Task<int> delay(int num)
{
await Task.Delay(15000);
return num;
}
Make your delayAsync method return Task.
public static async Task delayAsync(int num)
{
Console.WriteLine(await delay(num) + "time :" + DateTime.Now);
}
Wait for the result of the delayAsync in you Main method.
public static void Main(string[] args)
{
Console.WriteLine("## start ##");
for (var i = 0; i < 5; i++)
{
Console.WriteLine("counter: " + i);
delayAsync(i).Wait();
}
Console.WriteLine("## finished ##");
Console.Read();
}

You are not awaiting the Task.Delay
public static async Task<int> delay(int num){
await Task.Delay(15000);
return num;
}
Note that the signature of the method needs to include async. Additionally since you are now using await inside the method, you don't need to explicitly create a Task for the return statement.
Additionally you have to await the delayAsync call in your Main method (note that you cannot make Main async so you have to use a workaround like this: https://stackoverflow.com/a/9212343/868361

my desired output is to get the number one by one after the delay of 15 seconds
When you call an async method that you don't await then the compiler will start it and continue with the rest of the procedures. In your case with the rest of the loop. So the simple solution to get your desired output would be here:
Don't use async methods! Simply make it a serial processing.
To achieve that what you want using async you would have to wait in the loop for the delayAsync method. But this would make the asynchronous processing synchronous and you would end up again in the normal 1 thread serial processing, only having invested a lot of effort to end up from where you started.

Related

C# - async/await print order

I am trying to understand how async and await works so i wrote this little program to try and print "b" before "a" but it's not working and i can't figure it out.. any help? :)
public class program
{
static async Task Main()
{
await a();
b();
}
async static Task a()
{
Console.WriteLine("Waiting for a");
for (int i = 0; i < 100000000; i++)
if (i % 1000000 == 0)
Console.Write(".");
Console.WriteLine("\na");
}
static void b()
{
Console.WriteLine("b");
}
}
Lets refine your code. First it doesn't work, because you told the code to await a(), and so nothing after that line can run before (or during) it. Lets fix it:
static async Task Main()
{
var task = a();
b();
await task;
}
However that is not enough, it still doesn't work. It still runs a() before b() because your a method is not asynchronous. In fact it is synchronous. Just because you use async/await it doesn't make the code automatically asynchronous. You'll need more than that. One way is to add await Task.Yield() which is truely asynchronous call, even though it does nothing (except for allowing the switch to happen). Like this:
async static Task a()
{
Console.WriteLine("Waiting for a");
for (int i = 0; i < 100000000; i++)
if (i % 1000000 == 0)
{
Console.Write(".");
await Task.Yield();
}
Console.WriteLine("\na");
}
Now you will see b() running in the middle of a(). You can play around with the await Task.Yield(); call, and put it in different places to see different result.
This is still a bit primitive example. It would be better to make b() asynchronous as well. And use delays. Like this:
public class program
{
static async Task Main()
{
var task1 = a();
var task2 = b();
await task1;
await task2;
}
async static Task a()
{
Console.WriteLine("Waiting for a");
for (var i = 0; i < 100; i++)
{
Console.Write(".");
await Task.Delay(20);
}
Console.WriteLine("\na");
}
static async Task b()
{
await Task.Delay(200);
Console.WriteLine("b");
}
}
Note that I've slightly modified your a() so that it is more time dependent, less cpu-speed dependent.
Of course you have a thread-safety issue now, which in this case is ok since Console and Task methods are thread-safe. But generally you have to be aware that when two or more Tasks run concurrently then they may run on different threads, and thus you have to make the code thread-safe.
There are 2 problems.
Await is being used incorrectly
You use await to ensure whichever async method is called is completed before any subsequent code is executed.
As freakish said in his answer, you can assign the task from method a to a variable and await it after method b.
Method a isn't actually asynchronous
There isn't any thing that can actually be awaited in the method so it would just run synchronously and complete before method b. Adding something that can be awaited like Task.Yeild (as freakish has stated) would resolve the issue.
I would recommend reading more about asynchronous programming, here is a good place to start: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/

C# async method call with or without await call gives same result?

I have a simple program to test async/await, 2 versions: version 1 awaits another method inside async function, version doesn't:
Program 1:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("main starts..");
AsyncMethod();
Thread.Sleep(1000);
Console.WriteLine("main ends..");
Console.ReadLine();
}
static async void AsyncMethod()
{
Console.WriteLine("async starts");
var result = await MyMethod();
Console.WriteLine("async starts ends");
}
static async Task<int> MyMethod()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("async runs" + i.ToString() + "..");
await Task.Delay(1000);
}
return 0;
}
}
Program 2:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("main starts..");
AsyncMethod();
Thread.Sleep(1000);
Console.WriteLine("main ends..");
Console.ReadLine();
}
static async void AsyncMethod()
{
Console.WriteLine("async starts");
for (int i = 0; i < 5; i++)
{
Console.WriteLine("async runs" + i.ToString() + "..");
await Task.Delay(1000);
}
Console.WriteLine("async ends");
}
}
Both programs yields same result. I am just curious, do both program differs in what happens in the background?
I guess, program 1 will create 2 sub-threads, each level of "async" leads to a thread; program 2 will create 1 sub-thread. Right?
As long as "await" will wait until the task ends, then what's the difference from writing synchronous code? I think it just link creating several threads and call ".join()" for all of them. Right?
Both are async or Threaded programming using await means until your function execute your execution pointer will be hold on that functions it self and if you don't use wait it will pass on to next execution pointer mostly there is two reason behind adding await mostly in winform application while going for big process execution we may need to let software user to do the other work in the same form then we need to await the task. or some times we need get some data from one method so the method should be finished and next logic should execute in a new or other thread.

Task.Status should be Running but shows RanToCompletion

I'm puzzled with this situation, where a class has a method that launches two periodic Tasks and then a property is used to check if both Tasks are still running or not, but the result is unexpected. Here is the code (simplified):
public partial class UdpClientConnector
{
Task localListener;
Task periodicSubscriber;
bool keepWorking = false;
public bool IsRunning
{
get
{
if ((localListener != null) && (periodicSubscriber != null))
{
return (localListener.Status == TaskStatus.Running) &&
(periodicSubscriber.Status == TaskStatus.Running);
}
else
return false;
}
}
public void Start()
{
keepWorking = true;
localListener = new Task(() => LocalListenerWorker());
localListener.Start();
periodicSubscriber = new Task(() => PeriodicSubscriberWorker());
periodicSubscriber.Start();
}
public void Stop()
{
keepWorking = false;
localListener.Wait();
periodicSubscriber.Wait();
}
async void LocalListenerWorker()
{
while (keepWorking)
{
// Do some work and then wait a bit
await Task.Delay(1000);
}
}
async void PeriodicSubscriberWorker()
{
while (keepWorking)
{
// Do some (other) work and then wait a bit
await Task.Delay(1000);
}
}
}
To test this boilerplate I used the following:
UdpClientConnector connector = new UdpClientConnector();
// This assert is successful because the two Tasks are not yet started
Assert.IsTrue(!connector.IsRunning);
// Starts the tasks and wait a bit
Connector.Start();
Task.Delay(2000).Wait();
// This fails
Assert.IsTrue(connector.IsRunning);
When I've tried to debug the test case, I've found that two Tasks are in the RanToCompletion state, which is unexpected due the fact that both tasks are just loops and should not terminate until keepWorking becomes false.
I've tried also to start the Tasks using Task.Factory.StartNew(..) with same results.
What I'm missing? Thank you!
The problem is with how you start the tasks, and indeed the task methods.
localListener = new Task(() => LocalListenerWorker());
That task will complete when LocalListenerWorker returns - which it will do pretty much immediately (when it hits the first await expression). It doesn't wait for the asynchronous operation to actually complete (i.e. the loop to finish).
async void methods should almost never be used - they're basically only there to support event handlers.
I suggest you rewrite your methods to return Task, and then use Task.Run to start them, passing in a method group:
Task.Run(LocalListenerWorker);
...
private async Task LocalListenerWorker()
{
// Body as before
}
The task by Task.Run will only complete when the task returned by LocalListenerWorker completes, which is when the loop body finishes.
Here's a complete demo:
using System;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Task task1 = Task.Run(Loop);
// Don't do this normally! It's just as a simple demo
// in a console app...
task1.Wait();
Console.WriteLine("First task done");
Task task2 = new Task(() => Broken());
task2.Start();
// Don't do this normally! It's just as a simple demo
// in a console app...
task2.Wait();
Console.WriteLine("Second task done");
}
static async Task Loop()
{
for (int i = 0; i < 5; i++)
{
await Task.Delay(1000);
Console.WriteLine(i);
}
}
static async void Broken()
{
for (int i = 0; i < 5; i++)
{
await Task.Delay(1000);
Console.WriteLine(i);
}
}
}
The output shows:
0
1
2
3
4
First task done
Second task done
The first task behaves as expected, and only completes when the first async method has really completed. The second task behaves like your current code: it completes as soon as the second async method has returned - which happens almost immediately due to the await.

Understanding Task based asynchronous pattern C#

I am starting to study C# TAP coding. I don't understand why the code is running synchronously
async private void timer1_Tick(object sender, EventArgs e)
{
SyncCount++;
result1.Text = SyncCount.ToString();
AsyncCount = await CountForALongTimeAsync(AsyncCount);
result2.Text = AsyncCount.ToString();
}
async Task<int> CountForALongTimeAsync(int counter)
{
Thread.Sleep(3000);
counter++;
return counter;
}
async Task<int> CountForALongTimeAsync(int counter)
{
What comes next will be executed until the first awaited async call that actually does some waiting (it's possible that a given call could have all it needs to return immediately, e.g. a service that might hit the internet or might return data from a cache, in which case it won't wait).
There are no awaited calls at all, so the Task returned is returned already completed.
Since the calling await CountForALongTimeAsync is awaiting a task that is returned already completed, it runs synchronously.
The method would be better as:
async Task<int> CountForALongTimeAsync(int counter)
{
await Task.Delay(3000);
counter++;
return counter;
}
Incidentally, the pre await way of doing something very (but not entirely) similar would have been:
Task<int> CountForALongTimeAsync(int counter)
{
return Task.Delay(3000).ContinueWith(t =>
{
++counter;
return counter;
});
}
Considering that these are different ideas of "continuing" after a task might or might not give some insight.
In contrast the closest pre-await way of doing what the code in your question does was:
Task<int> CountForALongTimeAsync(int counter)
{
Thread.Sleep(3000);
counter++;
return Task.FromResult(counter); //FromResult returns an already completed task.
}

How to make a task more independent?

Originally I wrote my C# program using Threads and ThreadPooling, but most of the users on here were telling me Async was a better approach for more efficiency. My program sends JSON objects to a server until status code of 200 is returned and then moves on to the next task.
The problem is once one of my Tasks retrieves a status code of 200, it waits for the other Tasks to get 200 code and then move onto the next Task. I want each task to continue it's next task without waiting for other Tasks to finish (or catch up) by receiving a 200 response.
Below is my main class to run my tasks in parallel.
public static void Main (string[] args)
{
var tasks = new List<Task> ();
for (int i = 0; i < 10; i++) {
tasks.Add (getItemAsync (i));
}
Task.WhenAny (tasks);
}
Here is the getItemAsync() method that does the actual sending of information to another server. Before this method works, it needs a key. The problem also lies here, let's say I run 100 tasks, all 100 tasks will wait until every single one has a key.
public static async Task getItemAsync (int i)
{
if (key == "") {
await getProductKey (i).ConfigureAwait(false);
}
Uri url = new Uri ("http://www.website.com/");
var content = new FormUrlEncodedContent (new[] {
...
});
while (!success) {
using (HttpResponseMessage result = await client.PostAsync (url, content)) {
if (result.IsSuccessStatusCode) {
string resultContent = await result.Content.ReadAsStringAsync ().ConfigureAwait(false);
Console.WriteLine(resultContent);
success=true;
}
}
}
await doMoreAsync (i);
}
Here's the function that retrieves the keys, it uses HttpClient and gets parsed.
public static async Task getProductKey (int i)
{
string url = "http://www.website.com/key";
var stream = await client.GetStringAsync (url).ConfigureAwait(false);
var doc = new HtmlDocument ();
doc.LoadHtml (stream);
HtmlNode node = doc.DocumentNode.SelectNodes ("//input[#name='key']") [0];
try {
key = node.Attributes ["value"].Value;
} catch (Exception e) {
Console.WriteLine ("Exception: " + e);
}
}
After every task receives a key and has a 200 status code, it runs doMoreAsync(). I want any individual Task that retrieved the 200 code to run doMoreAsync() without waiting for other tasks to catch up. How do I go about this?
Your Main method is not waiting for a Task to complete, it justs fires off a bunch of async tasks and returns.
If you want to await an async task you can only do that from an async method. Workaround is to kick off an async task from the Main method and wait for its completion using the blocking Task.Wait():
public static void Main(string[] args) {
Task.Run(async () =>
{
var tasks = new List<Task> ();
for (int i = 0; i < 10; i++) {
tasks.Add (getItemAsync (i));
}
var finishedTask = await Task.WhenAny(tasks); // This awaits one task
}).Wait();
}
When you are invoking getItemAsync() from an async method, you can remove the ConfigureAwait(false) as well. ConfigureAwait(false) just makes sure some code does not execute on the UI thread.
If you want to append another task to a task, you can also append it to the previous Task directly by using ContinueWith():
getItemAsync(i).ContinueWith(anotherTask);
Your main problem seems to be that you're sharing the key field across all your concurrently-running asynchronous operations. This will inevitably lead to race hazards. Instead, you should alter your getProductKey method to return each retrieved key as the result of its asynchronous operation:
// ↓ result type of asynchronous operation
public static async Task<string> getProductKey(int i)
{
// retrieval logic here
// return key as result of asynchronous operation
return node.Attributes["value"].Value;
}
Then, you consume it like so:
public static async Task getItemAsync(int i)
{
string key;
try
{
key = await getProductKey(i).ConfigureAwait(false);
}
catch
{
// handle exceptions
}
// use local variable 'key' in further asynchronous operations
}
Finally, in your main logic, use a WaitAll to prevent the console application from terminating before all your tasks complete. Although WaitAll is a blocking call, it is acceptable in this case since you want the main thread to block.
public static void Main (string[] args)
{
var tasks = new List<Task> ();
for (int i = 0; i < 10; i++) {
tasks.Add(getItemAsync(i));
}
Task.WaitAll(tasks.ToArray());
}

Categories

Resources