I want to do some work with a coded in Delay with the UI active.
I thought I had TaskOfTResult_MethodSync fixed with Task.Delay(delay).Wait();. The problem is that blocks Task<int> taskS = TaskOfTResult_MethodSync(10000); it does not immediately move on to the await and the UI is not responsive. UI does not even paint until after the delay.
public async void TestTask3(int delay, CancellationToken ct) works but it does not let me return a value.
If I use
int rslt = TestTask3(1000, token).Result;
public async Task<int> TestTask3(int delay, CancellationToken ct)
It hangs on int rslt = TestTask3(1000, token).Result;
This is not valid syntax await TestTask3(1000, token);
I don't mind using public async void TestTask3(int delay, CancellationToken ct) but I would rather have work done with programmed Delay or Sleep that returns a value (rather than update a public property from the async method). What I want is to kick off a method / task then do some other work from the main tread. Then await. After the await some buttons get activated.
The reason I need a programmed in delay is it reads some instrument data and it needs to wait between reads to get a sample set.
Is there a way to get what I want?
I currently get what I need with BackGroundWorker but that but I was hoping to get there with task.
public MainWindow()
{
this.DataContext = this;
InitializeComponent();
Debug.WriteLine("before Task<int> taskS = TaskOfTResult_MethodSync(10000);");
Task<int> taskS = TaskOfTResult_MethodSync(10000);
Debug.WriteLine("before taskS.Wait");
taskS.Wait();
Debug.WriteLine("after taskS.Wait");
int i = taskS.Result;
Debug.WriteLine($"i = {i}");
Debug.WriteLine($"");
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
Debug.WriteLine("before TestTask3(1000, token);");
TestTask3(1000, token);
Debug.WriteLine("after TestTask3(1000, token);");
Thread.Sleep(2000);
Debug.WriteLine("after sleep on main TestTask3(1000, token);");
source.Cancel();
Debug.WriteLine("done Main");
}
public async void TestTask3(int delay, CancellationToken ct)
{
Debug.WriteLine($"TestTask3");
int ans = -1;
ans = await Task.Run(async () =>
{
// … do compute-bound work here
for (int j = 101; j <= 120; j++)
{
if(ct.IsCancellationRequested)
{
break;
}
await Task.Delay(delay);
ans = j;
Answer = j;
}
});
Debug.WriteLine($"TestTask3 {ans}");
Answer = ans;
//return ans;
}
Task<int> TaskOfTResult_MethodSync(int delay)
{
Debug.WriteLine($"TaskOfTResult_MethodSync delay = {delay} {DateTime.Now}");
int hours = 10;
Task.Delay(delay).Wait();
Debug.WriteLine($"TaskOfTResult_MethodSync after delay {DateTime.Now}");
return Task.FromResult(hours);
}
It's a bit unclear what you are trying to do here but both Wait() and Result will block synchronously.
You should make the TaskOfTResult_MethodSync method async and await Task.Delay:
async Task<int> TaskOfTResult_MethodSync(int delay)
{
Debug.WriteLine($"TaskOfTResult_MethodSync delay = {delay} {DateTime.Now}");
int hours = 10;
await Task.Delay(delay);
Debug.WriteLine($"TaskOfTResult_MethodSync after delay {DateTime.Now}");
return hours;
}
This makes the method asynchronous method.
Since the constructor is not asynchronous you could then move the invocation of the asynchronous method to a Loaded event handler. And TestTask3 should not return void if you want to be able to await it. Change the return type to Task and await this one also.
Finally, if call Thread.Sleep on the UI thread, your UI will indeed freeze. Use await Task.Delay if you want to "sleep" asynchronously:
public MainWindow()
{
this.DataContext = this;
InitializeComponent();
Loaded += async (s, e) =>
{
Debug.WriteLine("before Task<int> taskS = TaskOfTResult_MethodSync(10000);");
int i = await TaskOfTResult_MethodSync(10000);
Debug.WriteLine($"i = {i}");
Debug.WriteLine($"");
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
Debug.WriteLine("before TestTask3(1000, token);");
await TestTask3(1000, token);
Debug.WriteLine("after TestTask3(1000, token);");
await Task.Delay(2000);
Debug.WriteLine("after sleep on main TestTask3(1000, token);");
source.Cancel();
Debug.WriteLine("done Main");
};
}
public async Task TestTask3(int delay, CancellationToken ct)
{
Debug.WriteLine($"TestTask3");
await Task.Run(async () =>
{
// … do compute-bound work here
for (int j = 101; j <= 120; j++)
{
if (ct.IsCancellationRequested)
{
break;
}
await Task.Delay(delay);
ans = j;
Answer = j;
}
});
Debug.WriteLine($"TestTask3 {ans}");
Answer = ans;
}
One of the first issues that I noted in your code is that you are making all this async calls in your constructor (that's why you can't await TestTask3). I suggest you refer to this question to understand why this is bad.
Now, if you move your code to not be in your constructor, then you don't need to use the blocking constructs (like Wait() and .Result) and use await instead. For example, here is what TaskOfTResult_MethofSync implementation could look like:
private async Task<int> TaskOfTResult_MethodSync(int delay)
{
await Task.Delay(delay);
return Task.FromResult(10);
}
Note how instead of blocking on the .Delay call it now awaits
Related
How to cancel all tasks, if one of them return i.e. false (bool) result?
Is it possible to identify which task returned a result?
class Program
{
private static Random _rnd = new Random();
static void Main(string[] args)
{
var tasksCounter = _rnd.Next(4, 7);
var cts = new CancellationTokenSource();
var tasks = new Task<bool>[tasksCounter];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = CreateTask(cts);
}
Console.WriteLine("Waiting..");
Task.WaitAny(tasks);
Console.WriteLine("Done!");
Console.ReadKey();
}
private static Task<bool> CreateTask(CancellationTokenSource cts)
{
return Task.Factory.StartNew(TaskAction, cts.Token).Unwrap();
}
private static async Task<bool> TaskAction()
{
var delay = _rnd.Next(2, 5);
await Task.Delay(delay * 1000);
var taskResult = _rnd.Next(10) < 4;
return await Task.FromResult(taskResult);
}
}
I tried to use Task.WaitAll, Task.WaitAny etc, but none of these methods provide useful (in my case) functionality.
Edit:
As #ckuri stated in the comments, it would be easier to leverage the already existing properties of Task instead of writing a custom result class. Adjusted my answer accordingly.
One solution would be to check for the result in the CreateTask() method and pass a CancellationToken into your TaskAction() method:
private static Task<bool> CreateTask(CancellationTokenSource cts)
{
return Task.Run(async () =>
{
var result = await TaskAction(cts.Token);
// If result is false, cancel all tasks
if (!result)
cts.Cancel();
return result;
});
}
private static async Task<bool> TaskAction(CancellationToken token)
{
// Check for cancellation
token.ThrowIfCancellationRequested();
var delay = Rnd.Next(2, 5);
// Pass the cancellation token to Task.Delay()
await Task.Delay(delay * 1000, token);
var taskResult = Rnd.Next(10) < 4;
// Check for cancellation
token.ThrowIfCancellationRequested();
return taskResult;
}
Now you can do something like this in your Main method to receive all tasks which did not get cancelled:
try
{
// Wait for all tasks inside a try catch block because `WhenAll` throws a `AggregationException`
// containing a `TaskCanceledException`, if the token gets canceled
await Task.WhenAll(tasks);
}
catch { }
var tasksWithResult = tasks.Where(t => !t.IsCanceled).ToList();
I don't have an interpreter on hand, so excuse any mistakes. Your Task needs access to the token if you want to cancel all tasks from the task itself. See https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource?view=netcore-3.0 for an example. I.e. pass it as an argument to the task so one task can cancel the other tasks.
private static async Task<bool> TaskAction(CancellationTokenSource cts)
{
var delay = _rnd.Next(2, 5);
await Task.Delay(delay * 1000);
var taskResult = _rnd.Next(10) < 4;
if (!taskResult)
cts.Cancel()
return await Task.FromResult(taskResult);
}
Just be sure to capture the AggregateException and check if one of the inner excepts is an TaskCanceledException.
C# 8 adds support for asynchronuous iterator blocks, so you can await things and return an IAsyncEnumarator instead of an IEnumerable:
public async IAsyncEnumerable<int> EnumerateAsync() {
for (int i = 0; i < 10; i++) {
yield return i;
await Task.Delay(1000);
}
}
With a non-blocking consuming code that looks like this:
await foreach (var item in EnumerateAsync()) {
Console.WriteLine(item);
}
This will result in my code running for about 10 seconds. However, sometimes I want to break out of the await foreach before all elements are consumed. With an breakhowever, we would need to wait until the current awaited Task.Delay has finished. How can we break immediately out of that loop without waiting for any dangling async tasks?
The use of a CancellationToken is the solution since that is the only thing that can cancel the Task.Delay in your code. The way we get it inside your IAsyncEnumerable is to pass it as a parameter when creating it, so let's do that:
public async IAsyncEnumerable<int> EnumerateAsync(CancellationToken cancellationToken = default) {
for (int i = 0; i < 10; i++) {
yield return i;
await Task.Delay(1000, cancellationToken);
}
}
With the consuming side of:
// In this example the cancellation token will be caneled after 2.5 seconds
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(2.5));
await foreach (var item in EnumerateAsync(cts.Token)) {
Console.WriteLine(item);
}
Sure, this will cancel the enumeration after 3 elements were returned, but will end in an TaskCanceledException thrown out of Task.Delay. To gracefully exit the await foreach we have to catch it and break on the producing side:
public async IAsyncEnumerable<int> EnumerateAsync(CancellationToken cancellationToken = default) {
for (int i = 0; i < 10; i++) {
yield return i;
try {
await Task.Delay(1000, cancellationToken);
} catch (TaskCanceledException) {
yield break;
}
}
}
Note
As of now this is still in preview and is subject to possible change. If you are interested in this topic you can watch a discussion of the C# language team about CancellationToken in an IAsyncEnumeration.
I want to perform multiple loops in the same time using async Task (I don't want use Parallel.ForEach)
I do :
static async void Run()
{
await MultiTasks();
}
static async Task MultiTasks()
{
var Loop1 = Loop1Async();
var Loop2 = Loop2Async();
await Loop1;
await Loop2;
}
static async Task Loop1Async()
{
for (int i = 0; i < 500; i++)
{
Console.WriteLine("Loop 1 : " + i);
}
}
static async Task Loop2Async()
{
for (int i = 0; i < 500; i++)
{
Console.WriteLine("Loop 2 : " + i);
}
}
Run() is called in my Main method.
But the two loop is not executed in the same time. Once the first lap is completed, the second begins
Why and how to do this ?
You have the fundamental misunderstanding common to beginner users of await.
Let me be very clear about this. Await does not make something asynchronous. It asynchronously waits for an asynchronous operation to complete.
You are awaiting a synchronous operation. There is absolutely nothing asynchronous about the methods you are calling; await does not make them asynchronous. Rather, if they were asynchronous, then the await would return control to the caller immediately, so that the caller could continue to do work. When the asynchronous work finishes, then at some point in the future the remainder of the method is executed, with the awaited result.
Loop1Async and Loop2Async in fact are synchronous. Consider using WriteLineAsync method.
You can also use Task.WhenAll in MultiTasks.
Try .WhenAll(...)
static async Task MultiTasks()
{
var Loop1 = Loop1Async();
var Loop2 = Loop2Async();
await Task.WhenAll(Loop1, Loop2);
}
As others have noted your async methods do not currently yield execution.
You need something that will allow threads to yield back to the system so they can actually run in parallel. Something like this...
static async Task Loop1Async()
{
for (int i = 0; i < 500; i++)
{
Console.WriteLine("Loop 1 : " + i);
await Task.Yield();
}
}
static async Task Loop2Async()
{
for (int i = 0; i < 500; i++)
{
Console.WriteLine("Loop 2 : " + i);
await Task.Yield();
}
}
Your Loop1Async and Loop2Async methods does not have an await inside. For a method to be async it needs to have 1 or more await
I am trying to make part of my system run in parallel, but some some reason do it wait for each element before it starts the next even though i have not told it to await. I would like to start executing ExecuteItem for each this.Items and then continue when they are all done.
bool singleThread = false;
public async Task Execute()
{
if (!this.singleThread)
{
var tasks = this.Items.Select(x => this.ExecuteItem(x)).ToArray();
Task.WaitAll(tasks);
}
else
{
foreach (var item in this.Items)
{
await this.ExecuteItem(item);
}
}
}
private async Task ExecuteItem(IMyItem item)
{
MappedDiagnosticsContext.Set("itemRef", item.ItemRef);
try
{
await this.HandelItem(item);
}
catch (Exception exp)
{
Logger.ErrorException(string.Format("Execution for {0} failed.", item.ItemName), exp);
Logger.Error("Error Message: ", exp.Message);
}
MappedDiagnosticsContext.Remove("itemRef");
}
To make clear my problem my code behaves as if had wrote the following
var tasks = this.Items.Select(x => await this.ExecuteItem(x)).ToArray();
To make sure it was not some kind of linq problem have i rewriten the problem code to the following, however the code still blocks tasks[i] = this.ExecuteItem(this.Items[i]);
Task[] tasks = new Task[this.Items.Count];
for (int i = 0; i < this.Items.Count; i++)
{
Console.WriteLine("Adding " + this.Items[i].ItemName);
tasks[i] = this.ExecuteItem(this.Items[i]);
}
Console.WriteLine("Waiting!!!");
Task.WaitAll(tasks);
Something in HandelItem is blocking.
async methods don't run completely asynchronously, they execute synchronously up until the point they hit an await. So all of ExecuteItem, up to HandelItem will run before the tasks list is built. This synchronous behavior would continue into HandelItem if it is an async method, so likely HandelItem is executing while building up the tasks list.
This is easily seen with this example program:
static void Main(string[] args)
{
var items = Enumerable.Range(1, 2);
Console.WriteLine("Start");
var tasks = items.Select(i => AsyncMethod(i)).ToArray();
Console.WriteLine("Got tasks");
Task.WaitAll(tasks);
Console.WriteLine("Done!");
}
static async Task AsyncMethod(int i)
{
Console.WriteLine("Enter {0}", i);
await AsyncMethod2(i);
await Task.Delay(1000);
Console.WriteLine("Exit {0}", i);
}
static async Task AsyncMethod2(int i)
{
Console.WriteLine("Enter2 {0}", i);
await Task.Delay(2000);
Console.WriteLine("Exit2 {0}", i);
}
It's output is:
Start
Enter 1
Enter2 1
Enter 2
Enter2 2
Got tasks
Exit2 2
Exit2 1
Exit 1
Exit 2
Done!
So both async methods run while building the task list, up until the point that they have to wait. So if HandelItem does something non-asynchronous, it will cause blocking.
If you want the tasks to execute in parallel; and wait until all are complete:
await Task.WhenAll(this.Items.Select(item=>this.ExecuteItem(item)));
why does the method AwakeTest take 3 seconds instead of one
public static async void AwakeTest()
{
var Do1 = Sleep(1, 1);
var Do2 = Sleep(1, 2);
var Do3 = Sleep(1, 3);
await System.Threading.Tasks.Task.WhenAll(Do1, Do2, Do3);
Console.WriteLine(await Do1);
Console.WriteLine(await Do2);
Console.WriteLine(await Do3);
}
private static async System.Threading.Tasks.Task<int> Sleep(int Seconds, int ID)
{
if (Seconds < 0)
{
throw new Exception();
}
System.Threading.Thread.Sleep(Seconds * 1000);
return ID;
}
Since Thread.Sleep sleeps the thread, and each Task doesn't require to run in a separate thread, it hangs the entire thread.
You should use Task.Delay instead:
await Task.Delay(Seconds * 1000);