Asynchronous method in button click [duplicate] - c#

I'm starting to learn about async / await in C# 5.0, and I don't understand it at all. I don't understand how it can be used for parallelism. I've tried the following very basic program:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Task task1 = Task1();
Task task2 = Task2();
Task.WaitAll(task1, task2);
Debug.WriteLine("Finished main method");
}
public static async Task Task1()
{
await new Task(() => Thread.Sleep(TimeSpan.FromSeconds(5)));
Debug.WriteLine("Finished Task1");
}
public static async Task Task2()
{
await new Task(() => Thread.Sleep(TimeSpan.FromSeconds(10)));
Debug.WriteLine("Finished Task2");
}
}
}
This program just blocks on the call to Task.WaitAll() and never finishes, but I am not understanding why. I'm sure I'm just missing something simple or just don't have the right mental model of this, and none of the blogs or MSDN articles that are out there are helping.

I recommend you start out with my intro to async/await and follow-up with the official Microsoft documentation on TAP.
As I mention in my intro blog post, there are several Task members that are holdovers from the TPL and have no use in pure async code. new Task and Task.Start should be replaced with Task.Run (or TaskFactory.StartNew). Similarly, Thread.Sleep should be replaced with Task.Delay.
Finally, I recommend that you do not use Task.WaitAll; your Console app should just Wait on a single Task which uses Task.WhenAll. With all these changes, your code would look like:
class Program
{
static void Main(string[] args)
{
MainAsync().Wait();
}
public static async Task MainAsync()
{
Task task1 = Task1();
Task task2 = Task2();
await Task.WhenAll(task1, task2);
Debug.WriteLine("Finished main method");
}
public static async Task Task1()
{
await Task.Delay(5000);
Debug.WriteLine("Finished Task1");
}
public static async Task Task2()
{
await Task.Delay(10000);
Debug.WriteLine("Finished Task2");
}
}

Understand C# Task, async and await
C# Task
Task class is an asynchronous task wrapper. Thread.Sleep(1000) can stop a thread running for 1 second. While Task.Delay(1000) won't stop the current work. See code:
public static void Main(string[] args){
TaskTest();
}
private static void TaskTest(){
Task.Delay(5000);
System.Console.WriteLine("task done");
}
When running," task done" will show up immediately. So I can assume that every method from Task should be asynchronous. If I replace TaskTest () with Task.Run(() =>TaskTest()) task done won't show up at all until I append a Console.ReadLine(); after the Run method.
Internally, Task class represent a thread state In a State Machine. Every state in state machine have several states such as Start, Delay, Cancel, and Stop.
async and await
Now, you may wondering if all Task is asynchronous, what is the purpose of Task.Delay ? next, let's really delay the running thread by using async and await
public static void Main(string[] args){
TaskTest();
System.Console.WriteLine("main thread is not blocked");
Console.ReadLine();
}
private static async void TaskTest(){
await Task.Delay(5000);
System.Console.WriteLine("task done");
}
async tell caller, I am an asynchronous method, don't wait for me. await inside the TaskTest() ask for waiting for the asynchronous task. Now, after running, program will wait 5 seconds to show the task done text.
Cancel a Task
Since Task is a state machine, there must be a way to cancel the task while task is in running.
static CancellationTokenSource tokenSource = new CancellationTokenSource();
public static void Main(string[] args){
TaskTest();
System.Console.WriteLine("main thread is not blocked");
var input=Console.ReadLine();
if(input=="stop"){
tokenSource.Cancel();
System.Console.WriteLine("task stopped");
}
Console.ReadLine();
}
private static async void TaskTest(){
try{
await Task.Delay(5000,tokenSource.Token);
}catch(TaskCanceledException e){
//cancel task will throw out a exception, just catch it, do nothing.
}
System.Console.WriteLine("task done");
}
Now, when the program is in running, you can input "stop" to cancel the Delay task.

Your tasks never finish because they never start running.
I would Task.Factory.StartNew to create a task and start it.
public static async Task Task1()
{
await Task.Factory.StartNew(() => Thread.Sleep(TimeSpan.FromSeconds(5)));
Debug.WriteLine("Finished Task1");
}
public static async Task Task2()
{
await Task.Factory.StartNew(() => Thread.Sleep(TimeSpan.FromSeconds(10)));
Debug.WriteLine("Finished Task2");
}
As a side note, if you're really just trying to pause in a async method, there's no need to block an entire thread, just use Task.Delay
public static async Task Task1()
{
await Task.Delay(TimeSpan.FromSeconds(5));
Debug.WriteLine("Finished Task1");
}
public static async Task Task2()
{
await Task.Delay(TimeSpan.FromSeconds(10));
Debug.WriteLine("Finished Task2");
}

Async and await are markers which mark code positions from where control should resume after a task (thread) completes.
Here's a detail youtube video which explains the concept in a demonstrative manner http://www.youtube.com/watch?v=V2sMXJnDEjM
If you want you can also read this coodeproject article which explains the same in a more visual manner.
http://www.codeproject.com/Articles/599756/Five-Great-NET-Framework-4-5-Features#Feature1:-“Async”and“Await”(Codemarkers)

static void Main(string[] args)
{
if (Thread.CurrentThread.Name == null)
Thread.CurrentThread.Name = "Main";
Console.WriteLine(Thread.CurrentThread.Name + "1");
TaskTest();
Console.WriteLine(Thread.CurrentThread.Name + "2");
Console.ReadLine();
}
private async static void TaskTest()
{
Console.WriteLine(Thread.CurrentThread.Name + "3");
await Task.Delay(2000);
if (Thread.CurrentThread.Name == null)
Thread.CurrentThread.Name = "FirstTask";
Console.WriteLine(Thread.CurrentThread.Name + "4");
await Task.Delay(2000);
if (Thread.CurrentThread.Name == null)
Thread.CurrentThread.Name = "SecondTask";
Console.WriteLine(Thread.CurrentThread.Name + "5");
}
If you run this program you will see that await will use different thread. Output:
Main1
Main3
Main2
FirstTask4 // 2 seconds delay
SecondTask5 // 4 seconds delay
But if we remove both await keywords, you will learn that async alone doesn't do much. Output:
Main1
Main3
Main4
Main5
Main2

Related

Call async method after another async method is finished in C#

I want to call step2 method after step 1 is finished. With this code below the methods step 1 and step 2 are executing in parallel. And of course I they need to be asynchronous so they won't block step 3 from executing.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace test
{
internal class Program
{
static void Main(string[] args)
{
async void step1()
{
await Task.Run(() =>
{
Thread.Sleep(2000);
Console.WriteLine("step 1");
});
}
async void step2()
{
await Task.Run(() =>
{
Thread.Sleep(5000);
Console.WriteLine("step 2");
});
}
void step3()
{
Console.WriteLine("step 3");
}
step1();
step2();
step3();
// the code below is not working but just and idea
// what I want to make. If it at all posible
// step1().step2()
// step3()
Console.ReadLine();
}
}
}
Any help would be greatly appreciated. Keep in mind I am beginner in C#!
Edit:
I know that I can get the end result even with this code.
void step1()
{
Thread.Sleep(2000);
Console.WriteLine("step 1");
}
void step2()
{
Thread.Sleep(5000);
Console.WriteLine("step 2");
}
void step3()
{
Console.WriteLine("step 3");
}
step3();
step1();
step2();
even without async/await at all.
The point of this question is to make small proof of concept application where even though the code is set up like this:
step1();
step2();
step3();
where step3() is set last will execute first because has no delay and also step2() will have to wait for step1() to finish.
Is this at all possible with async/await in C#. I think this can be done with promises in javascript.
There may be a misunderstanding about how asynchronous methods work. All async methods start running synchronously, just like any other method. The magic happens when await acts on a Task that is incomplete. At that point, the method returns a new incomplete Task to the calling method (or returns nothing if it's void, which is why you should avoid async void).
So if you call step1() first, then step1() will start executing first - there is no way around that. But when step1() hits await Task.Run(...) then it returns and the Main method continues executing. At that point, you can decide what to do. Do you want to wait until step1() completes or go do something else?
Here is what the code would look like if you want:
step1() to start executing first.
step2() to only start after step1() completes.
step3() executes as soon as possible after step1() starts, but without waiting for step1() to complete.
static async Task Main(string[] args)
{
async Task step1()
{
Console.WriteLine("step 1 starting");
await Task.Run(() =>
{
Thread.Sleep(2000);
Console.WriteLine("step 1 done");
});
}
async Task step2()
{
Console.WriteLine("step 2 starting");
await Task.Run(() =>
{
Thread.Sleep(5000);
Console.WriteLine("step 2 done");
});
}
void step3()
{
Console.WriteLine("step 3");
}
var step1task = step1();
step3();
await step1task;
await step2();
Console.ReadLine();
}
The output is:
step 1 starting
step 3
step 1 done
step 2 starting
step 2 done
If you want step3() to execute before step1() even starts executing, then you need to call step3() first - no way around it.
If you change your Main method (as well as step1 and step2) to async Task instead of void (or async void), you'll be able to await your methods.
static async Task Main(string[] args)
{
async Task step1()
{
await Task.Run(() =>
{
Thread.Sleep(2000);
Console.WriteLine("step 1");
});
}
async Task step2()
{
await Task.Run(() =>
{
Thread.Sleep(5000);
Console.WriteLine("step 2");
});
}
void step3()
{
Console.WriteLine("step 3");
}
step3(); // You can put step3 here if you want it to run before step1 and step2.
await step1();
await step2();
Console.ReadLine();
}
I suggest you check this Microsoft article to get a better understanding of async Task vs async void.
If the constraints are
step2 should start when step1 ends
step1 and step2 should not block step3
Calling code must be (e.g. no ContinueWith)
step1();
step2();
step3();
Then the answer is this is not possible.
Unless you have control of the code inside the steps, and do thread signalling to prevent step2 to start before step1 ends. Read about ManualResetEvent.
static void Main(string[] args)
{
var mre = new ManualResetEvent(false);
void step1()
{
Task.Run(() =>
{
Thread.Sleep(1000);
Console.WriteLine("step 1");
mre.Set();
});
}
void step2()
{
Task.Run(() =>
{
mre.WaitOne();
Console.WriteLine("step 2");
});
}
void step3()
{
Console.WriteLine("step 3");
}
step1();
step2();
step3();
Console.ReadLine();
}
Drop the async, it is not meaning what you think. Use ContinueWith
Task step1()
{
return Task.Run(() =>
{
Thread.Sleep(2000);
Console.WriteLine("step 1");
});
}
Task step2()
{
return Task.Run(() =>
{
Thread.Sleep(5000);
Console.WriteLine("step 2");
});
}
void step3()
{
Console.WriteLine("step 3");
}
var task = step1()
.ContinueWith(x => step2());
step3();
task.Wait();

Does await pass control to the caller? Or does await suspend the thread? Why does the top level call need an await?

1 thread is running the program.
It prints Main Method Started....
Then prints Some Method Started....
Then I was expecting that await Task.Delay will release the thread into the pool until the Task delay completes. But that seems to happen only if the call to SomeMethod would have been like this: await SomeMethod();
In the current example it prints Main Method End.... Does await pass control to the caller? Or does await suspend the thread?
using System;
using System.Threading.Tasks;
namespace AsynchronousProgramming
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Main Method Started......");
SomeMethod();
Console.WriteLine("Main Method End");
Console.ReadKey();
}
public async static void SomeMethod()
{
Console.WriteLine("Some Method Started......");
//Thread.Sleep(TimeSpan.FromSeconds(10));
await Task.Delay(TimeSpan.FromSeconds(10));
Console.WriteLine("\n");
Console.WriteLine("Some Method End");
}
}
}

Timeout for long running 3rd library method

I want to add ability to cancel long running external method (in code below is it LongOperation method from SomeExternalClass class), so I wrap this method into task and add custom task extension for handle timeout.
TimeoutException is successful throwed after specific period of time, but external method is not canceled. How I can cancel LongOperation?
class Program
{
private static CancellationTokenSource cancellationTokenSource;
static async Task Main(string[] args)
{
cancellationTokenSource = new CancellationTokenSource();
cancellationTokenSource.Token.ThrowIfCancellationRequested();
try
{
await SearchTask().WithTimeout(TimeSpan.FromSeconds(2));
}
catch (TimeoutException)
{
Console.WriteLine("Timeout");
cancellationTokenSource.Cancel();
}
Console.WriteLine("Program end");
Console.ReadKey();
}
private static Task SearchTask()
{
return Task.Run(() =>
{
Console.WriteLine("Start task");
SomeExternalClass.LongOperation();
Console.WriteLine("End task");
}, cancellationTokenSource.Token);
}
}
public static class SomeExternalClass
{
// this is simulation of long running 3rd party method
public static void LongOperation()
{
Console.WriteLine("Start LongOperation");
Thread.Sleep(10000);
Console.WriteLine("End LongOperation");
}
}
public static class TaskExtension
{
public static async Task WithTimeout(this Task task, TimeSpan timeout)
{
if (task == await Task.WhenAny(task, Task.Delay(timeout)))
{
await task;
}
throw new TimeoutException();
}
}
The output is:
Start task
Start LongOperation
Timeout
Program end
End LongOperation
End task

Async Task method WaitingForActivation

I have found a very confusing behavior of async methods. Consider the following Console app:
private static int _i = 0;
private static Task<int> _calculateTask = Task.FromResult(0);
private static int _lastResult = 0;
static void Main(string[] args)
{
while (true)
{
Console.WriteLine(Calculate());
}
}
private static int Calculate()
{
if (!_calculateTask.IsCompleted)
{
return _lastResult;
}
_lastResult = _calculateTask.Result;
_calculateTask = CalculateNextAsync();
return _lastResult;
}
private static async Task<int> CalculateNextAsync()
{
return await Task.Run(() =>
{
Thread.Sleep(2000);
return ++_i;
});
}
As expected, after it is launched, it first prints out a bunch of 0s, then ones, twos and so on.
In contrast consider the following UWP app snippet:
private static int _i = 0;
private static Task<int> _calculateTask = Task.FromResult(0);
private static int _lastResult = 0;
public int Calculate()
{
if (!_calculateTask.IsCompleted)
{
return _lastResult;
}
_lastResult = _calculateTask.Result;
_calculateTask = CalculateNextAsync();
return _lastResult;
}
private static async Task<int> CalculateNextAsync()
{
return await Task.Run( async() =>
{
await Task.Delay(2000);
return ++_i;
});
}
private void Button_Click(object sender, RoutedEventArgs e)
{
while( true)
{
Debug.WriteLine(Calculate());
}
}
Although these two differ only in one small detail, the UWP snippet just keeps printing out 0 and task state in the if statement just stays Waitingforactivation. Furthermore the problem can be fixed by removing async and await from CalculateNextAsync:
private static Task<int> CalculateNextAsync()
{
return Task.Run(async () =>
{
await Task.Delay(2000);
return ++_i;
});
}
Now everything works the same way as in the Console app.
Can someone explain the reason why the behavior in Console differs from UWP app? And why the task stays as c in case of UWP app?
Update
I have got back to this question again, but found out an issue that the originally accepted answer does not cover - the code on UWP never reaches the .Result, it just keeps checking for IsCompleted which returns false, hence the _lastResult is returned. What makes the Task have a AwaitingActivation state when it should have completed?
Solution
I figured out that the reason is that the active waiting while loop prevents the await continuation from ever seizing the UI thread again, hence causing a "deadlock"-like situation.
Based on the code in the UWP app there is no need for holding on to the _calculateTask. Just await the task.
Here is the updated code
private static int _i = 0;
private static int _lastResult = 0;
public async Task<int> Calculate() {
_lastResult = await CalculateNextAsync();
return _lastResult;
}
//No need to wrap the code in a Task.Run. Just await the async code
private static async Task<int> CalculateNextAsync()
await Task.Delay(2000);
return ++_i;
}
//Event Handlers allow for async void
private async void Button_Click(object sender, RoutedEventArgs e) {
while( true) {
var result = await Calculate();
Debug.WriteLine(result.ToString());
}
}
ORIGINAL ANSWER
You are mixing async/await and blocking calls like .Result in the UWP app which is causing a deadlock because of its one chunk SynchronizationContext. Console applications are an exception to that rule, which is why it works there and not in the UWP app.
The root cause of this deadlock is due to the way await handles
contexts. By default, when an incomplete Task is awaited, the current
“context” is captured and used to resume the method when the Task
completes. This “context” is the current SynchronizationContext unless
it’s null, in which case it’s the current TaskScheduler. GUI and
ASP.NET applications have a SynchronizationContext that permits only
one chunk of code to run at a time. When the await completes, it
attempts to execute the remainder of the async method within the
captured context. But that context already has a thread in it, which
is (synchronously) waiting for the async method to complete. They’re
each waiting for the other, causing a deadlock.
Note that console applications don’t cause this deadlock. They have a
thread pool SynchronizationContext instead of a one-chunk-at-a-time
SynchronizationContext, so when the await completes, it schedules the
remainder of the async method on a thread pool thread. The method is
able to complete, which completes its returned task, and there’s no
deadlock. This difference in behavior can be confusing when
programmers write a test console program, observe the partially async
code work as expected, and then move the same code into a GUI or
ASP.NET application, where it deadlocks.
Reference Async/Await - Best Practices in Asynchronous Programming

Can I use async / await to simulate a background worker?

I'm trying to avoid having to chain a bunch of BackgroundWorkers together. I'm doing something that requires me to wait for the UI to update before continuing execution. Obviously, I can't use Sleep, as this blocks the UI thread from updating and defeats the purpose. I found the code below which I thought was the answer, but it appears the task.Wait(); line is still blocking the UI thread.
static void Main(string[] args)
{
var task = Task.Run(() => DoSomething());
task.Wait();
// once the task completes, now do more
}
static void DoSomething()
{
// something here that is looking for the UI to change
}
I also tried the following, which did the same thing:
static void Main(string[] args)
{
var task = Task.Run(() => DoSomethingAsync());
task.Wait();
// once the task completes, now do more
}
private async Task DoSomethingAsync()
{
// something here that is looking for the UI to change
}
Is it possible to do what I want, and if so, what am I doing wrong?
You need to await the task instead of blocking on it. You can do that inside an async method.
Now, Main can't be async but an event handler can be (which I guess is where you actually use that code):
public async void EventHandler(object sender, EventArgs e)
{
await Task.Run(() => DoSomething()); // wait asynchronously
// continue on the UI thread
}
Note that it's async void which should only be used on event handlers. All other async methods should return a task.
Using Task.Run means your using a ThreadPool thread. To really wait asynchronously for the UI to "do something" you should use TaskCompletionSource. You create it and await it's Task property and you complete that task when the UI changed:
public async void EventHandler(object sender, EventArgs e)
{
_tcs = new TaskCompletionSource<bool>();
await _tcs.Task;
}
public void UIChanged(object sender, EventArgs e)
{
_tcs.SetResult(false);
}

Categories

Resources