Why the async tasks not executed correctly? [duplicate] - c#

This question already has answers here:
Running multiple async tasks and waiting for them all to complete
(10 answers)
Closed 2 years ago.
I have a project to submit job to AWS state machine and monitor the job status. So I implement the code like following pseudo code:
Two tasks are calling in the main function:
public static void Main(string[] args)
{
ExeJobs("1").Wait();
MonitorJobs().Wait();
}
In MonitoryJobs task, do something like:
public static async Task MonitorJobs()
{
int retry = 0;
for (int i = 0; i < retry; i++)
{
// Check History event here if find job id. else keep looping;
....
}
}
In ExeJobs task, do something like:
public static async Task ExeJobs(string jobId)
{
await SubmitJob(jobId);
ExecutionStatus status = ExecutionStatus.RUNNING;
while (status == ExecutionStatus.RUNNING)
{
status = await MonitorJobStaus(jobId);
}
}
I expected the MonitorJobs() is a thread keep live till I find the job execute status when it's running ExeJobs(). However it looks the MonitorJobs() task cannot start before ExeJobs() finish its while(status == ExecutionStatus.RUNNING) loop.
I wish MonitorJobs() can be running during the while loop in the other task and it should be expected result since they are two threads.
Anyone knows what's wrong here? Thanks

Wait will synchronously block until the task completes. So the current
thread is literally blocked waiting for the task to complete. As a
general rule, you should use "async all the way down"; that is, don't
block on async code.
public static async Task Main(string[] args)
{
await ExeJobs("1");
await MonitorJobs();
}

Wait will block until the task is finished. Also How your program will behave will be depended on what actually is happening inside your async tasks. You can use Task.WhenAll (making your main method async):
public static async Task Main(string[] args)
{
await Task.WhenAll(ExeJobs, MonitorJobs);
}
This will start both tasks (assuming that ExeJobs is actually asynchronous) and wait until both finish.

So you need to understand that when you await something, execution in that scope stops until the task is completed. If you want to have the execution keep going without waiting for it to finish, you need to assign it to a task and you can wait for it to finish after.
public static async Task Main(string[] args)
{
// start ExeJobs task but don't wait for it to finish
var jobTasks = ExeJobs("1");
// start monitor task but don't wait for it to finish
var monitorTask = MonitorJobs();
// wait for both tasks to finish before returning
await Task.WhenAll(jobTasks, monitorTask);
}

Related

Return data from long running Task on demand

I want to create a Task, which may run for many minutes, collecting data via an API call to another system. At some point in the future I need to stop the task and return the collected data. This future point is unknown at the time of starting the task.
I have read many question about returning data from tasks, but I can't find any that answer this scenario. I may be missing a trick, but all of the examples actually seem to wait in the man thread for the task to finish before continuing. This seems counter-intuitive, surely the purpose of a task is to hand off an activity whilst continuing with other activities in your main thread?
Here is one of those many examples, taken from DotNetPearls..
namespace TaskBasedAsynchronousProgramming
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine($"Main Thread Started");
Task<double> task1 = Task.Run(() =>
{
return CalculateSum(10);
});
Console.WriteLine($"Sum is: {task1.Result}");
Console.WriteLine($"Main Thread Completed");
Console.ReadKey();
}
static double CalculateSum(int num)
{
double sum = 0;
for (int count = 1; count <= num; count++)
{
sum += count;
}
return sum;
}
}
}
Is it possible to do what I need, and have a long-running task running in parallel, stop it and return the data at an arbitrary future point?
Here is a sample application how you can do that:
static double partialResult = -1;
static void Main()
{
CancellationTokenSource calculationEndSignal = new(TimeSpan.FromSeconds(3));
Task meaningOfLife = Task.Run(() =>
GetTheMeaningOfLife(calculationEndSignal.Token),
calculationEndSignal.Token);
calculationEndSignal.Token.Register(() => Console.WriteLine(partialResult));
Console.ReadLine();
}
static async Task GetTheMeaningOfLife(CancellationToken cancellationToken)
{
foreach (var semiResult in Enumerable.Range(1, 42))
{
partialResult = semiResult;
cancellationToken.ThrowIfCancellationRequested();
await Task.Delay(1000);
}
}
partialResult is a shared variable between the two threads
The worker thread (GetTheMeaningOfLife) only writes it
The main thread (Main) only reads it
The read operation is performed only after the Task has been cancelled
calculationEndSignal is used to cancel the long-running operation
I've have specified a timeout, but you can call the Cancel method if you want
meaningOfLife is the Task which represents the long-running operation call
I have passed the CancellationToken to the GetTheMeaningOfLife and to the Task.Run as well
For this very simple example the Task.Run should not need to receive the token but it is generally a good practice to pass there as well
Register is receiving a callback which should be called after the token is cancelled
ReadLine can be any other computation
I've used ReadLine to keep the application running
GetTheMeaningOfLife simply increments the partialResult shared variable
either until it reaches the meaning of life
or until it is cancelled
Here is one approach. It features a CancellationTokenSource that is used as a stopping mechanism, instead of its normal usage as a cancellation mechanism. That's because you want to get the partial results, and a canceled Task does not propagate results:
CancellationTokenSource stoppingTokenSource = new();
Task<List<int>> longRunningTask = Task.Run(() =>
{
List<int> list = new();
for (int i = 1; i <= 60; i++)
{
if (stoppingTokenSource.IsCancellationRequested) break;
// Simulate a synchronous operation that has 1 second duration.
Thread.Sleep(1000);
list.Add(i);
}
return list;
});
Then, somewhere else in your program, you can send a stopping signal to the task, and then await asynchronously until the task acknowledges the signal and completes successfully. The await will also propagate the partial results:
stoppingTokenSource.Cancel();
List<int> partialResults = await longRunningTask;
Or, if you are not in an asynchronous workflow, you can wait synchronously until the partial results are available:
stoppingTokenSource.Cancel();
List<int> partialResults = longRunningTask.Result;

Using Task.Delay() closes program [duplicate]

This question already has answers here:
How can I call an async method in Main?
(9 answers)
Closed 2 years ago.
I try to use Task.Delay() but when the program gets there, it simpy closes itself no matter what. E.g in that case the program cant even reach the Console.Write("*"); line, it closes. What am i doing wrong? Any idea?
(Example code)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Whatever
{
class Program
{
static async Task WriteAsync()
{
while (true)
{
await Task.Delay(1000);
Console.Write("*");
}
}
static void Main(string[] args)
{
WriteAsync();
}
}
}
What Patrick Roberts said in the Question comments, make your main method async.
It's helpful to know what's going on, so I'll try break it down.
Task.Delay(1000) returns a task, and that task must be awaited somewhere (and it is).
However the Task that's awaiting Task.Delay(1000) is returned by WriteAsync and the main method isn't awaiting that task (ergo the Task.Delay(1000) isn't actually being awaited anywhere).
The main method runs a method which returns a task, then - immediately - it exits, the work of the task could have started, but nothing is (a)waitng for it to finish, so the program terminates with that task unfinished.
Now in the main method you could have WriteAsync().Wait().
However this isn't recommended for lots of reasons, but mainly because you're synchronously calling an async method, and while it will work with this simple program, it is a sure fire way to introduce deadlocks into your program.
Instead, change your main method to be async.
When writing async code, it needs to be async all the way down
static async Task Main(string[] args)
{
await WriteAsync();
}
Question So if I had numerous asynchronous methods in the main, at least one of them would have to be awaited, else the program would just finish before the tasks could run
Answer No, all tasks would have to be awaited.
static async Task Main(string[] args)
{
WriteAsync01();
await WriteAsync02();
}
If WriteAsync02() completes before WriteAsync01() the program will terminate before WriteAsync01() completes, which is not what you want.
static async Task Main(string[] args)
{
await WriteAsync01();
await WriteAsync02();
}
This will await both the tasks in sequence, So WriteAsync01() runs to completion before WriteAsync01() starts, this may not be what you want.
static async Task Main(string[] args)
{
var task1 = WriteAsync01();
var task2 = WriteAsync02();
await task1;
await task2;
}
Will start both tasks, but the program will wait for both tasks to complete before terminating. Alternatively, this is identical to the above.
static async Task Main(string[] args)
{
var task1 = WriteAsync01();
var task2 = WriteAsync02();
await Task.WhenAll(task1, task2);
}
Since WriteAsync() is not awaited in Main the Program continues after calling the async task and actually finishes before the Task is completed.

Async method blocking on unawaited task

In my current project, I have a piece of code that, after simplifying it down to where I'm having issues, looks something like this:
private async Task RunAsync(CancellationToken cancel)
{
bool finished = false;
while (!cancel.IsCancellationRequested && !finished)
finished = await FakeTask();
}
private Task<bool> FakeTask()
{
return Task.FromResult(false);
}
If I use this code without awaiting, I end up blocking anyway:
// example 1
var task = RunAsync(cancel); // Code blocks here...
... // Other code that could run while RunAsync is doing its thing, but is forced to wait
await task;
// example 2
var task = RunAsync(cancelSource.Token); // Code blocks here...
cancelSource.Cancel(); // Never called
In the actual project, I'm not actually using FakeTask, and there usually will be some Task.Delay I'm awaiting in there, so the code most of the time doesn't actually block, or only for a limited amount of iterations.
In unit testing, however, I'm using a mock object that does pretty much do what FakeTask does, so when I want to see if RunAsync responds to its CancellationToken getting cancelled the way I expect it to, I'm stuck.
I have found I can fix this issue by adding for example await Task.Delay(1) at the top of RunAsync, to force it to truly run asynchronous, but this feels a bit hacky. Are there better alternatives?
You have an incorrect mental picture of what await does. The meaning of await is:
Check to see if the awaitable object is complete. If it is, fetch its result and continue executing the coroutine.
If it is not complete, sign up the remainder of the current method as the continuation of the awaitable and suspend the coroutine by returning control to the caller. (Note that this makes it a semicoroutine.)
In your program, the "fake" awaitable is always complete, so there is never a suspension of the coroutine.
Are there better alternatives?
If your control flow logic requires you to suspend the coroutine then use Task.Yield.
Task.FromResult actually runs synchronously, as would await Task.Delay(0). If you want to actually simulate asynchronous code, call Task.Yield(). That creates an awaitable task that asynchronously yields back to the current context when awaited.
As #SLaks said, your code will run synchronously. One thing is running async code, and another thing is running parallel code.
If you need to run your code in parallel you can use Task.Run.
class Program
{
static async Task Main(string[] args)
{
var tcs = new CancellationTokenSource();
var task = Task.Run(() => RunAsync("1", tcs.Token));
var task2 = Task.Run(() => RunAsync("2", tcs.Token));
await Task.Delay(1000);
tcs.Cancel();
Console.ReadLine();
}
private static async Task RunAsync(string source, CancellationToken cancel)
{
bool finished = false;
while (!cancel.IsCancellationRequested && !finished)
finished = await FakeTask(source);
}
private static Task<bool> FakeTask(string source)
{
Console.WriteLine(source);
return Task.FromResult(false);
}
}
C#'s async methods execute synchronously up to the point where they have to wait for a result.
In your example there is no such point where the method has to wait for a result, so the loop keeps running forever and thereby blocking the caller.
Inserting an await Task.Yield() to simulate some real async work should help.

Wait() method of a task bloks the Task

I am working in Xamarin where I have a Task that I start at the first menupage, go through several other menupages, and then want to wait for it's completion when opening an endpage. To do this I save the task in a static field when starting it:
private static Task myTask;
public static void sync(User user)
{
if (myTask== null || myTask.IsCompleted) {
myTaskStarted = true;
//Note: do not trust on the variable being filled in immediately after the start of the task. It takes a minute. Use the flag
myTask= AsyncMyTask(user);
}
}
And then later I call a method from another page that is simply supposed to wait for myTask to finnish by calling myTask.Wait() after doing some checks on myTask having been started and not being null. But I see that once I call myTask.Wait() myTask is stuck and no longer progresses in the debugger. It's stuck. If I replace myTask.Wait() by myTask.Wait(1000) myTask is frozen for the duration of the timeout. After the timeout it continues. This is not the behaviour that is described in the documentation. Can anyone explain why the AsyncMyTask method is blocked when you call myTask.Wait() from the UI thread?
As requested: the AwaitMyTask method:
public async static Task<Boolean> AwaitMyTask()
{
if(!myTaskStarted && myTask== null)
{
return false;
} else
{
while (myTask== null)
{
Task.Delay(10);
}
}
//Stuck on the line below
myTask.Wait();
myTaskStarted = false;
return myTask.IsCompleted;
}
Task.Wait is a synchronously awaiting the task which blocks the thread. Unless you can point to a documentation stating something else, I'd say that it's expected behavior as described in https://msdn.microsoft.com/en-us/library/dd235635(v=vs.110).aspx
Wait is a synchronization method that causes the calling thread to wait until the current task has completed. ...

When should Task.Run() be used?

What's the difference between these two approaches:
public static int Main(string[] args)
{
string result;
Task.Run(async () =>
{
Task<string> getStringTask = GetStringAsync();
result = await validationsTask;
}).Wait();
Console.WriteLine(result);
}
and
public static int Main(string[] args)
{
Task<string> getStringTask = GetStringAsync();
getStringTask.Wait();
string result = getStringTask.Result;
Console.WriteLine(result);
}
I've seen a lot of people using the first approach and I'm not sure why. Is there any particular advantage? Which one is recommended for waiting async methods inside main of a Console Application?
Is there any particular advantage?
Usually with async methods the operation is initialized synchronously and then the wait can be asynchronous with await or syncrhnous with Wait(). The Main method can't be async so you are force to block with Wait() there or you can do a Console.ReadKey() to run until the user presses a key.
Task.Run(async () => ... ) can be quite useful when the async operation is expensive to initialize. That way you allow the main thread to continue while the operation is initializing.
Which one is recommended for waiting async methods inside main of a Console Application?
I would use a slightly modified version of the second approach. You can add a MainAsync method and call that from Main then you can use await inside it.
public static async Task MainAsync()
{
string result = await GetStringAsync();
Console.WriteLine(result);
}
public static int Main(string[] args)
{
MainAsync().Wait();
}
Also with console apps there is no risk of deadlock as there is no SynchronizationContext and the default thread pool one gets used.
The first approach continues execution after the asynch function is finished using a thread pool thread while the second approach continues execution using the calling thread that starts the asynch function.
With the second approach, there is a possibility of deadlocks. For example (similar to an example extracted from the book CLR via C#):
public static int Main(string[] args)
{
Task<string> getStringTask = GetStringAsync();
string result = getStringTask.Result; //the main thread is blocked waiting.
Console.WriteLine(result);
}
public Task<string> GetStringAsync()
{
// Issue the HTTP request and let the thread return from GetHttp
HttpResponseMessage msg = await new HttpClient().GetAsync("http://Wintellect.com/");
// We never get here: The main thread is waiting for this method to finish but this method
// can't finish because the main thread is waiting for it to finish --> DEADLOCK!
return await msg.Content.ReadAsStringAsync();
}
So the first approach avoids this problem:
public static int Main(string[] args)
{
string result;
Task.Run(async () =>
{
// We run on a thread pool thread
Task<string> getStringTask = GetStringAsync();
// We do get here because any thread pool thread can execute this code, we don't need the main thread.
result = await validationsTask;
}).Wait();
Console.WriteLine(result);
}
Another solution is using ConfigureAwait(false), extracted from the book:
Passing true to this method gives you the same behavior as not calling
the method at all. But, if you pass false, the await operator does
not query the calling thread’s SynchronizationContext object and, when
a thread pool thread completes theTask, it simply completes it and the
code after the await operator executes via the thread pool thread.
public Task<string> GetStringAsync()
{
HttpResponseMessage msg = await new HttpClient().GetAsync("http://Wintellect.com/").ConfigureAwait(false);
// We DO get here now because a thread pool can execute this code
// as opposed to forcing the main thread to execute it.
return await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
}

Categories

Resources