How to determine the status of the job Async/Await - c#

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.

Related

In C# an async task waits to finish another async task before it executes

I have this test methods,
private async Task<int> TestOnly()
{
await Task.Delay(10000);
using (StreamWriter sw = File.AppendText(#"asyncTest.txt"))
{
sw.WriteLine($"2 Written TestOnly().");
}
return 100;
}
private async Task TestAgain()
{
await Task.Delay(0);
using (StreamWriter sw = File.AppendText(#"syncTest.txt"))
{
sw.WriteLine($"1 Written here TestAgain().");
}
}
Private async Task Refresh()
{
await TestOnly();
await TestAgain();
}
If I call the Refresh(), what I am expecting that in syncTest.txt, the text 1 Written here TestAgain(). will print first than 2 Written TestOnly(). because the TestOnly() method awaiting 10 seconds before it writes into the asyncTest.txt. But when I run, it waits for it. Why is that?
When you await a task, you cause execution of the current method to suspend until the task is completed. Don't await a task until you're ready to wait for it.
private async Task Refresh()
{
var task1 = TestOnly();
var task2 = TestAgain();
await Task.WhenAll(task1, task2);
}
You can also accomplish the whole thing without async or await. If you can see why, I think it will help you understand what await does.
private Task Refresh()
{
var task1 = TestOnly();
var task2 = TestAgain();
return Task.WaitAll(task1, task2);
}
This may also help: How do yield and await implement control of flow in .NET?

Do something periodically while waiting for result of an GetAsync

I want to start an GetAsync or PostAsync and then in a loop do something and check for results.
req1 = client.GetAsync(url_1); // a time consuming request
do
{
//do something here
var req2= await client.GetAsync(url_2);
var result2 = await req2.Content.ReadAsStringAsync();
} while (!IsResultReady(req1)); // check if url_1 job is done and stop the loop
var result1 = await req1.Content.ReadAsStringAsync();
this example should give you what you need
async Task Main()
{
var mainTask = MyLongRunningTask();
// mainTask is already started without await
do
{
await DoSomethingElse();
} while (!mainTask.IsCompleted);
}
public async Task MyLongRunningTask()
{
Console.WriteLine("Long Running Task Started");
await Task.Delay(3000); // simulating client.GetAsync(url_1)
Console.WriteLine("Long Running Task Finished");
}
async Task DoSomethingElse()
{
Console.WriteLine("doing some other tasks");
await Task.Delay(1000);
}
output:
Long Running Task Started
doing some other tasks
doing some other tasks
doing some other tasks
Long Running Task Finished

How to implement tasks with two awaiting points, using async/await

I have some asynchronous operations that consist of two distinct stages. Initially I want to await them until the completion of their first stage, and later await them until their final completion. Here is a simplified version of these operations:
async Task<string> TwoStagesAsync()
{
Console.WriteLine($"Stage 1 Started");
await Task.Delay(1000); // Simulate an I/O operation
bool resultOfStage1 = true;
Console.WriteLine($"Stage 1 Finished");
if (!resultOfStage1) return null;
/* Stage separator */
Console.WriteLine($"Stage 2 Started");
await Task.Delay(1000); // Simulate an I/O operation
Console.WriteLine($"Stage 2 Finished");
return "Hello!";
}
To achieve this requirement I had the idea of representing these two-stage operations as nested tasks: Task<Task<string>>. This would allow me to await initially the outer task, and later await the result of the outer task, which would be the inner task. This is my currently best attempt to implement this idea:
async Task<Task<string>> TwoStagesNestedAsync_A() // Problematic
{
Console.WriteLine($"Stage 1 Started");
await Task.Delay(1000); // Simulate an I/O operation
bool resultOfStage1 = true;
Console.WriteLine($"Stage 1 Finished");
if (!resultOfStage1) return Task.FromResult((string)null);
/* Stage separator */
return Task.Run(async () =>
{
Console.WriteLine($"Stage 2 Started");
await Task.Delay(1000); // Simulate an I/O operation
Console.WriteLine($"Stage 2 Finished");
return "Hello!";
});
}
What I like to this solution is that it works and it is quite readable, since it doesn't require any special synchronization primitives like SemaphoreSlim or TaskCompletionSource. What I don't like is that the second stage is executed in the ThreadPool context instead of the initial SynchronizationContext. Is there any way to make it use the current SynchronizationContext from start to finish, without complicating it too much?
I should include one more of my failed attempts. Replacing the Task.Run with a local async function doesn't work, because for some reason the line Console.WriteLine($"Stage 2 Started") is executed as part of the first stage, instead of the second stage.
async Task<Task<string>> TwoStagesNestedAsync_B() // Problematic
{
Console.WriteLine($"Stage 1 Started");
await Task.Delay(1000); // Simulate an I/O operation
bool resultOfStage1 = true;
Console.WriteLine($"Stage 1 Finished");
if (!resultOfStage1) return Task.FromResult((string)null);
return SecondStageAsync();
async Task<string> SecondStageAsync()
{
Console.WriteLine($"Stage 2 Started");
await Task.Delay(1000); // Simulate an I/O operation
Console.WriteLine($"Stage 2 Finished");
return "Hello!";
}
}
Update: Here is an example of consuming an asynchronous operation that consists of two stages:
Task<Task<string>>[] operations = Enumerable.Range(1, 10)
.Select(_ => TwoStagesNestedAsync_A())
.ToArray();
/* Do something else before awaiting Stage 1 */
Task<string>[] innerTasks = await Task.WhenAll(operations);
Console.WriteLine($"Stage 1 is now complete");
/* Do something else before awaiting Stage 2 */
string[] results = await Task.WhenAll(innerTasks);
Console.WriteLine($"Stage 2 is now complete");
I assume you want to execute something when first stage is complete.
You can pass an action as parameter to the function.
public async Task<string> TwoStagesAsync(Func<Task> injectedAction)
{
await ExecuteStageOne();
// Execute without "stopping" second stage
var injectedTask = injectedAction.Invoke();
if (somethingFailed) return null;
/* Stage separator */
await ExecuteStageTwo();
await injectedTask; // Make sure it completes without errors
return "Hello!";
}
After update
Requirements tell us that consumer of the TwoStages method do know that operation has two stages and this consumer want execute some action between every stage.
So we need to expose tasks of every state to the consumer.
If you wrap TwoStages method within a class, you can expose more details for its consumers.
We write code in object-oriented programming language anyway, isn't it ;)
public class TwoStageOperation
{
public TwoStageOperation() { }
public async Task ExecuteFirstStage()
{
Console.WriteLine($"Stage 1 Started");
await Task.Delay(1000);
Console.WriteLine($"Stage 1 Finished");
}
public async Task<string> ExecuteLastStage()
{
Console.WriteLine($"Stage 2 Started");
await Task.Delay(1000);
Console.WriteLine($"Stage 2 Finished");
return "Hello";
}
}
Usage
var operations = Enumerable.Range(1, 10)
.Select(_ => new TwoStageOperation())
.ToArray();
/* Do something else before awaiting Stage 1 */
await Task.WhenAll(operations.Select(op => op.ExecuteFirstStage());
Console.WriteLine($"Stage 1 is now complete");
/* Do something else before awaiting Stage 2 */
string[] results = await Task.WhenAll(operations.Select(op => op.ExecuteLastStage());
Console.WriteLine($"Stage 2 is now complete");
In case operations has different implementations, you can introduce an interface and have different implementations
public interface ITwoStageOperation
{
Task ExecuteFirstStage();
Task<string> ExecuteLastStage();
}
var operations = new ITwoStageOperation[]
{
new LandTwoStageOperation(),
new OceanTwoStageOperation(),
new AirTwoStageOperation(),
};
Alternative approach
Which I think you will prefer more, because you were very close to it :), would be to return a function as result of first stage
public async Task<Func<Task<string>>> TwoStagesAsync()
{
await ExecuteStageOne();
Func<Task<string>> lastStage = async () =>
{
await Task.Delay(1000);
return "Hello";
};
return lastStage;
}
Usage
var firstStages = Enumerable.Range(1, 10)
.Select(_ => TwoStagesAsync())
.ToArray();
/* Do something else before awaiting Stage 1 */
var lastStages = await Task.WhenAll(firstStages);
Console.WriteLine($"Stage 1 is now complete");
/* Do something else before awaiting Stage 2 */
string[] results = await Task.WhenAll(lastStages.Select(s => s.Invoke());
Console.WriteLine($"Stage 2 is now complete");
Try this.
public static async Task<bool> FirstStageAsync() // Problematic
{
Console.WriteLine($"Stage 1 Started");
await Task.Delay(1000); // Simulate an I/O operation
bool resultOfStage1 = true;
Console.WriteLine($"Stage 1 Finished");
return await Task.FromResult(resultOfStage1);
}
public static async Task<string> SecondStageAsync()
{
Console.WriteLine($"Stage 2 Started");
await Task.Delay(1000); // Simulate an I/O operation
Console.WriteLine($"Stage 2 Finished");
return "Hello!";
}
Then you can call it by:
var task = FirstStageAsync().ContinueWith(async d =>
{
if (d.IsCompleted)
{
var resultOfStage1 = await d;
if (resultOfStage1)
{
var task2 = SecondStageAsync();
task2.Wait();
}
}
});
task.Wait();
Is that you want to achieve?
Be careful with deadlock.
Good Luck!

Don't return from action until task ends

I am a little bit lost in async tasks within ASP.NET Web API action. I have an action:
[HttpPost]
public async Task<HttpResponseMessage> Restart()
{
await AspManager.Restart();
return Request.CreateResponse(HttpStatusCode.OK, new { result = "Success", message = "IIS site successfully restarted" });
}
Restart may be long running and I want to wait for it and then return a response. Here is the long running code:
public static async Task<Task> Restart()
{
var client = new Client("...");
CheckApiKey(client);
var task = Task.Factory.StartNew(async () =>
{
client.Stop();
await Task.Delay(5 * 1000);
throw new BusinessException("test");
client.Start();
});
return await task;
}
So in main Restart method I am checking a key, then I should stop a service, wait 5 seconds and start a service. Action from the controller should not return until this work is done. But the problem is that action returns and after 5 seconds BusinessException is thrown.
Your method is an async Task<Task>, and you're starting a task and returning that. This means you're returning a task has just started.
Key point being: you're awaiting the task creation, not its execution.
Change your method signature to be an "async void", then, from await Task.Factory.StartNew(() => versus Task.Start; await Task;, use Task.Run():
public async Task Restart()
{
// ...
await Task.Run(async () =>
{
client.Stop();
await Task.Delay(5 * 1000);
client.Start();
});
}
Task.Factory.StartNew is a dangerous API, as I explain on my blog. The problem you're running into is that it doesn't understand async lambdas. (There are other problems, too).
However, using Task.Run is not an appropriate solution. It's counterproductive on ASP.NET. You should just use await by itself:
public static async Task<Task> RestartAsync()
{
var client = new Client("...");
if (CheckApiKey(client))
return;
client.Stop();
await Task.Delay(TimeSpan.FromSeconds(5));
client.Start();
}

How to cancel other threads as soon as one completed thread satisfies condition

I have an ASP.NET MVC application which needs to check if something exists at 3 remote API servers. The application passes an ID to each API and it returns either true or false. The code looks like this.
public class PingController
{
public async Task<bool> IsFound(int id)
{
var servers = new ['a.com', b.com', 'c.com'];
var result = await foundAtServers(id, servers);
return result;
}
private async Task<bool> foundAtServers(int id, string[] servers)
{
var tasks = from server in servers
select checkServer(id, server);
return await.Task.WhenAll(tasks.ToArray());
}
private async Task<bool> checkServer(id, server)
{
var request = new HttpRequestMessage(HttpMethod.Get, server+"/api/exists"+id);
var client = new HttpClient();
var task = await client.SendAsync(request);
var response = await task.Content.ReadAsStringAsync();
return bool.Parse(response);
}
}
This code currently checks all 3 APIs asynchronously but will wait until ALL of the HttpClient calls have completed before the MVC Action can return.
As soon as one API returns true I want to immediately return true on the Action, rather than wait for the other tasks to complete.
The C# Task class has .WaitAll and .WaitAny, but these won't work either. As I need to cancel the other HttpClient request, I presume I need to use a CancellationToken but I don't know how to use it with this structure.
Cheers.
If you want to immediately return, you can use Task.WhenAny instead of Task.WhenAll. This won't cancel the on-going tasks, but it will enable you to return as soon as possible:
private async Task<bool> FoundAtServersAsync(int id, string[] servers)
{
var tasks = (from server in servers
select checkServer(id, server)).ToList();
while (tasks.Count > 0)
{
var finishedTask = await Task.WhenAny(tasks);
if (finishedTask.Result)
{
return finishedTask.Result;
}
tasks.Remove(finishedTask);
}
return false;
}
This will discard the other tasks. This means that if any exception is thrown inside one of them, it will be swallowed.
Edit:
If you care about actually canceling the other tasks, consider passing your CancellationToken to the overload of SendAsync which takes one, and calling CancellationTokenSource.Cancel once a value is received. Note this will mean you'll also need to handle the OperationCanceledException they will throw.
If they don't matter, i'd simply discard them as above.
This problem is made easier by using the following method to take a sequence of tasks and order them based on when they are completed.
public static IEnumerable<Task<T>> Order<T>(this IEnumerable<Task<T>> tasks)
{
var taskList = tasks.ToList();
var taskSources = new BlockingCollection<TaskCompletionSource<T>>();
var taskSourceList = new List<TaskCompletionSource<T>>(taskList.Count);
foreach (var task in taskList)
{
var newSource = new TaskCompletionSource<T>();
taskSources.Add(newSource);
taskSourceList.Add(newSource);
task.ContinueWith(t =>
{
var source = taskSources.Take();
if (t.IsCanceled)
source.TrySetCanceled();
else if (t.IsFaulted)
source.TrySetException(t.Exception.InnerExceptions);
else if (t.IsCompleted)
source.TrySetResult(t.Result);
}, CancellationToken.None,
TaskContinuationOptions.PreferFairness,
TaskScheduler.Default);
}
return taskSourceList.Select(tcs => tcs.Task);
}
With this you can write:
public static async Task<bool> WhenAny(this IEnumerable<Task<bool>> tasks)
{
foreach (var task in tasks.Order())
if (await task)
return true;
return false;
}
You could wait for the first task to complete - if it's successful, return true immediately. Otherwise, wait for the next one to complete, and so on and so forth.
private async Task<bool> foundAtServers(int id, string[] servers)
{
var tasks = servers.Select(server => checkServer(id, server))
.ToList();
while(tasks.Any())
{
var task = await Task.WhenAny(tasks);
if(task.Result)
return true;
tasks.Remove(task);
}
return false;
}

Categories