Do something periodically while waiting for result of an GetAsync - c#

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

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?

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!

Skip the await task response conditional

I have the following code:
//Await #1
var response1 = await doSomething();
if(response1.isSuccess) {
//Await #2
var response2 = await doSomethingElse();
}
Response 1 and response 2 are totally independent and i want to parallelize the await task here.
Basically response 2 takes a lot of time and hence is only invoked when response1 is success.
Is there any way in which i can invoke both tasks and see the result of response 1 and if it is fail, i drop/skip the response of Await#2.
Essentially what you want is to cancel a task, but with a little more logic.
You need to edit doSomethingElse so that it accepts a CancellationToken, and also so that it makes use of it to stop what its doing:
public async Task<Foo> DoSomethingElse(CancellationToken token) {
...
if (token.IsCancellationRequested) {
// stop what you are doing...
// I can't tell you how to implement this without seeing how DoSomethingElse is implemented
}
...
}
Now, get a CancellationToken from a CancellationTokenSource:
var source = new CancellationTokenSource();
var token = source.Token;
And here comes the logic of "if response 1 fails cancel response 2":
var response2Task = DoSomethingElse(token);
var response1 = await DoSomething();
if (!response1.IsSuccess) {
source.Cancel();
} else {
var response2 = await response2Task;
}
var task2 = doSomethingElse();
var response1 = await doSomething();
if(response1.isSuccess) {
var response2 = await task2;
}
This will start the execution of doSomethingElse() immediately, and only wait for its completion when response1.isSuccess == true
You can launch both threads, then once the first task obtains a result, you could either stop, or 'wait' for the second thread to finish.
The conditional logic, imo, should be placed in the first task's thread. If you do not have access to the doSomething, make a lambda in which you will await doSomething's response and then proceed with the condition logic.
How to stop a thread? Here you go, and here you go
This is what you can do:
var task1 = Task.Run(() =>
{
Console.WriteLine("running task 1");
return 1;
});
var task2 = Task.Run(() =>
{
Console.WriteLine("running task 2");
return 2;
});
await Task.WhenAll(task1, task2);
So you will run the 2 tasks in parallel. If you need to check the result of particular tasks, this is the way to do that(it won't trigger the task again if you run Task.WhenAll() previously. It will just get you the results of previously executed tasks):
var result1 = await task1;
var result2 = await task2;
Then you can apply some condition:
if(result1 == 1) return result2;
etc..

How to wait for later started task

In my code sample main thread doesn't wait when task2 is finished.
public async Task Run()
{
Console.WriteLine("Main start");
await getTask1();
Console.WriteLine("Main 2");
var task2 = getTask2();
await Task.Delay(1);
Console.WriteLine("Main 3");
task2.Start();
await task2;
Console.WriteLine("Main end");
}
private async Task getTask1()
{
Console.WriteLine("task1 start");
await Task.Delay(100);
Console.WriteLine("task1 end");
}
private Task getTask2()
{
return new Task(async () =>
{
Console.WriteLine("task2 start");
await Task.Delay(100);
Console.WriteLine("task2 end");
});
}
Result of execution this code is
Main start
task1 start
task1 end
Main 2
Main 3
task2 start
Main end
task2 end
How can I change code where 'Main end' will be at the end of list.
In getTask2 you're starting a Task that just starts another Task. So when you await that Task it will continue executing as soon as it has finished starting the inner task, not when that inner task has finished.
In this case there's no reason at all for you to create a new task just to start a new task in the first place; you should just use the approach used in the first method.
Of course, if, for some reason, you do need to create a new Task just to start a new task then you need to get the inner Task out and ensure that the main method only continues executing when that inner Task has finished. There is an Unwrap method to create a Task that is logically equivalent to a Task that is the Result of another Task:
private Task getTask2()
{
Task<Task> task = new Task<Task>(async () =>
{
Console.WriteLine("task2 start");
await Task.Delay(100);
Console.WriteLine("task2 end");
});
task.Start();
return task.Unwrap();
}
But you don't even need to do that. Task.Run will automatically unwrap the value for you if it is given a lambda that produces a Task:
private Task getTask2()
{
return Task.Run(async () =>
{
Console.WriteLine("task2 start");
await Task.Delay(100);
Console.WriteLine("task2 end");
});
}
And once again, this is all assuming that just starting the asynchronous operation needs to be offloaded to another thread, which should be very rare. Usually this means that there's a bug in that asynchronous method in that it shouldn't be doing long running synchronous work before giving you its Task in the first place, but on occasion that method will be from an external library that you don't control, so this would be your only option.
The constructor overload for Task that you are using has the following signature:
public Task(Action action)
Although you can assign the following expression to a variable of type Action:
async () =>
{
Console.WriteLine("task2 start");
await Task.Delay(100);
Console.WriteLine("task2 end");
}
this action will point to a synchronous function that will synchronously finish once the await in await Task.Delay(100); is reached (although the rest of the "action" will continue asynchronously). So, as far as the Task object is concerned, the execution of this Action is completed once this await is reached. This means that the await in await task2; will asynchronously continue at that point which explains why "Main end" is printed before "task2 end".
So basically, the constructor for Task does not support asynchronous actions, just synchronous ones.
To fix this problem, you need to start a task using a method that understands asynchronous actions. An asynchronous action looks like this: Func<Task>.
The Task.Run method supports asynchronous actions because it has the following overload:
public static Task Run(Func<Task> function)
So to fix your code, change return new Task(... to return Task.Run(... and then don't call the Start method on the returned task since Task.Run will create a Task that is already started.
If you want to delay the execution of the second "task", then I suggest to make the getTask2 method return Func<Task> (an asynchronous action) instead of Task like this:
private Func<Task> getTask2()
{
return async () =>
{
Console.WriteLine("task2 start");
await Task.Delay(100);
Console.WriteLine("task2 end");
};
}
And then run such asynchronous action when you want from the Run method like this:
public async Task Run()
{
Console.WriteLine("Main start");
await getTask1();
Console.WriteLine("Main 2");
var task2 = getTask2(); //construct asynchronous action
Console.WriteLine("Main 3");
await Task.Run(task2); //execute the asynchronous action
Console.WriteLine("Main end");
}
new Task( does not work with async functions by itself. You are creating a Task<Task>, you need to call Unwrap() before you await the inner task.
private Task<Task> getTask2()
{
return new Task(async () =>
{
Console.WriteLine("task2 start");
await Task.Delay(100);
Console.WriteLine("task2 end");
});
}
var task2 = getTask2();
Console.WriteLine("Main 3");
task2.Start();
await task2.Unwrap();
You have an error in your code. You have not marked the getTask2 method with the keyword async yet you await its result. Even though you are using an async delegate within the method you must use the async keyword if it is to be successfully awaited.
Here's an idea as to how you can accomplish your desired result.
public async Task Run()
{
Console.WriteLine("Main start");
await getTask1();
await getTask2();
Console.WriteLine("Main end");
}
public async Task AlternateRun()
{
Console.WriteLine("Main start");
List<Task> task_list = new List<Task>();
task_list.Add(getTask1());
task_list.Add(getTask2());
var task_result = Task.WhenAll(task_list);
task_result.Wait();
Console.WriteLine("Main end");
}
private async Task getTask1()
{
Console.WriteLine("task1 start");
await Task.Delay(100);
Console.WriteLine("task1 end");
}
private async Task getTask2()
{
Console.WriteLine("task2 start");
await Task.Delay(100);
Console.WriteLine("task2 end");
}
I have also added an AlternateRun method that will demonstrate an alternative style of awaiting multiple tasks. If you need your tasks to be completed in order then consider using the ContinueWith extension method.
Notice that I also removed your task2.Start()statement. This is already implied by the await keyword.
Hope this helps.

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.

Categories