Windows Form gets stuck on multiple async tasks - c#

I am trying to execute parallel methods, but Form gets stuck whenever
I call them.
Please correct what I am doing wrong. Here is the Code:
public partial class Form1 : Form
{
private async void button1_Click(object sender, EventArgs e)
{
var itemList = new List<string>() { "Field1", "Field2", "Field3" };
await Task.WhenAll(itemList.Select(item =>
new WorkToDo(item).StartWork()
));
}
}
public class WorkToDo
{
private string id;
public WorkToDo(string id)
{
this.id = id;
}
public async Task<bool> StartWork()
{
Calculate();
Analyze();
SomeToDo();
var result = Save();
await Task.Delay(100);
return result;
}
private bool Calculate()
{
//Some complex and time taking calculation will be here
return true;
}
private bool Analyze()
{
//Some complex and time taking calculation will be here
return true;
}
private bool SomeToDo()
{
//Some complex and time taking calculation will be here
return true;
}
private bool Save()
{
//Some complex and time taking calculation will be here
return true;
}
}

You need to remember that normal async / await will still be performed on the UI thread.
So to be sure that a real long action is pushed to a background thread, you need to wrap it in Task.Run... like Task.Run(() => Task.WhenAll(tasks));
To complete the question a bit more ( seeing the other answer available ), Task.Run usage is not something to take lightly. It all depends on what sort of code needs to be wrapped.
There is a good write up series on this up on the blog of Stephen Cleary here http://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-even-in.html so take some time to go through this and see what fits your project.
Or look here for some other details from Stephen https://stackoverflow.com/a/18015586

The problem that you have is that StartWork claims to be asynchronous, and yet it isn't. It does all of it's work synchronously.
Marking a method as async doesn't make it asynchronous. it just allows you to use the await keyword from within that method. If you perform long running synchronous operations from an async method then that method is still going to be doing that work synchronously.
There are really two approaches to take here. If there are some number of the things done in StartWork that really are inherently asynchronous, then you need to wrap whatever synchronous CPU bound work you have in calls to Task.Run so that the synchronous work that you have can be done asynchronously in a thread pool thread.
If there is no inherently asynchronous operations you have to do in StartWork then make the method clearly synchronous. Have it return a boolean, not a Task, and adjust the name to reflect the fact that it is synchronous. Then have the caller that calls it use Task.Run to do that whole operation on a thread pool thread asynchronously.
Having StartWork falsely claim to be asynchronous, and then still using Task.Run to do the purportedly asynchronous work in another thread is going to be extremely confusing to other readers of your code, as there should be no reason to offload an asynchronous method to a non-UI thread.

IMHO, If you are using Async operation you don't need Task.Run() if you have Sync Task and do it asynchronously you need Task.Run()
If you are using normal synchronous process just return Task<T> and use this Task.Run(()) to use background thread to process. See this answer
private async void button1_Click(object sender, EventArgs e)
{
var itemList = new List<string>() { "Field1", "Field2", "Field3" }; // more than 50 items
Task.Run(() => Task.WhenAll(tasks));
}
public class WorkToDo
{
private string id;
public WorkToDo(string id)
{
this.id = id;
}
public async Task<bool> StartWork()
{
var t1 = Calculate();
var t2 = Analyze();
var t3 = SomeToDo();
//Assuming you need to do all this before you save
// so wait for the all.
await Task.WhenAll(t1,t2,t3);
var result = await Save();
return result;
}
private async Task<bool> Calculate()
{
//Some complex and time taking calculation will be here
//Assuming here you have some DoAsync() method
return true;
}
private async Task<bool> Analyze()
{
//Some complex and time taking calculation will be here
return true;
}
private async Task<bool> SomeToDo()
{
//Some complex and time taking calculation will be here
return true;
}
private async Task<bool> Save()
{
//Some complex and time taking calculation will be here
return true;
}
Using WhenAll() has some advantage like propagating all error at once, see this

Related

Is this usage of Task.Run() bad practice?

If the use of Task.Run in this case justifiable ?
Currently I run this code in a WinForms app, but later on it will be used in a ASP.NET project as a HostedService/BackgroundService. I am not sure if this is comparable then.
After reading multiple blogs about async/await and Tasks I feel like the Task.Run(() => .. should be implemented in the calling method Manager.SyncLoop(). But what if the implementation of IConnection is truely asynchronous, wouldn't that be code smell ?
private async void button1_Click(object sender, EventArgs e)
{
// this should be handled by the BackgroudService, WinForms is used just for testing
var m = new Manager();
m.Connection = new ConnectionA();
m.ExecuteAsync();
}
}
public interface IConnection
{
Task<object> ReadAsync();
}
// assume that i cannot change this
public class SomeLib
{
private Random random = new Random();
public object SyncReading()
{
Thread.Sleep(5000);
return random.Next(); ;
}
}
public class ConnectionA : IConnection
{
private SomeLib lib = new SomeLib();
public Task<object> ReadAsync()
{
// is this usage of Task.Run ok?
var v = Task.Run(() => lib.SyncReading());
return v;
}
// this will block UI
//public Task<object> ReadAsync()
//{
// return Task.FromResult(lib.SyncReading());
//}
}
public class Manager
{
public IConnection Connection { get; set; }
public async Task ExecuteAsync()
{
await SyncLoop();
}
public async Task SyncLoop()
{
while (true)
{
var i = await Connection.ReadAsync();
await Task.Delay(2000);
}
}
}
First, can you change IConnection? Is this synchronous implementation the primary one, or is it just one of many?
If you can change IConnection, then make it synchronous, and you can use Task.Run in the implementation of ExecuteAsync.
If IConnection needs to remain asynchronous, then I would say to implement ConnectionA.ReadAsync synchronously. Then have the Task.Run in ExecuteAsync as normal. The key behind this technique is that an asynchronous (Task-returning) signature means that the implementation may be asynchronous, not that it must be asynchronous.

How to pause task running on a worker thread and wait for user input?

If I have a task running on a worker thread and when it finds something wrong, is it possible to pause and wait for the user to intervene before continuing?
For example, suppose I have something like this:
async void btnStartTask_Click(object sender, EventArgs e)
{
await Task.Run(() => LongRunningTask());
}
// CPU-bound
bool LongRunningTask()
{
// Establish some connection here.
// Do some work here.
List<Foo> incorrectValues = GetIncorrectValuesFromAbove();
if (incorrectValues.Count > 0)
{
// Here, I want to present the "incorrect values" to the user (on the UI thread)
// and let them select whether to modify a value, ignore it, or abort.
var confirmedValues = WaitForUserInput(incorrectValues);
}
// Continue processing.
}
Is it possible to substitute WaitForUserInput() with something that runs on the UI thread, waits for the user's intervention, and then acts accordingly? If so, how? I'm not looking for complete code or anything; if someone could point me in the right direction, I would be grateful.
What you're looking for is almost exactly Progress<T>, except you want to have the thing that reports progress get a task back with some information that they can await and inspect the results of. Creating Progress<T> yourself isn't terribly hard., and you can reasonably easily adapt it so that it computes a result.
public interface IPrompt<TResult, TInput>
{
Task<TResult> Prompt(TInput input);
}
public class Prompt<TResult, TInput> : IPrompt<TResult, TInput>
{
private SynchronizationContext context;
private Func<TInput, Task<TResult>> prompt;
public Prompt(Func<TInput, Task<TResult>> prompt)
{
context = SynchronizationContext.Current ?? new SynchronizationContext();
this.prompt += prompt;
}
Task<TResult> IPrompt<TResult, TInput>.Prompt(TInput input)
{
var tcs = new TaskCompletionSource<TResult>();
context.Post(data => prompt((TInput)data)
.ContinueWith(task =>
{
if (task.IsCanceled)
tcs.TrySetCanceled();
if (task.IsFaulted)
tcs.TrySetException(task.Exception.InnerExceptions);
else
tcs.TrySetResult(task.Result);
}), input);
return tcs.Task;
}
}
Now you simply need to have an asynchronous method that accepts the data from the long running process and returns a task with whatever the user interface's response is.
You can use TaskCompletionSource to generate a task that can be awaited within the LongRunningTask.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ConsoleApp5
{
class Program
{
private static event Action<string> Input;
public static async Task Main(string[] args)
{
var inputTask = InputTask();
var longRunningTask = Task.Run(() => LongRunningTask());
await Task.WhenAll(inputTask, longRunningTask);
}
private static async Task InputTask()
{
await Task.Yield();
while(true)
{
var input = await Console.In.ReadLineAsync();
Input?.Invoke(input);
}
}
static async Task<bool> LongRunningTask()
{
SomeExpensiveCall();
var incorrectValues = GetIncorrectValuesFromAbove();
if (incorrectValues.Count > 0)
{
var confirmedValues = await WaitForUserInput(incorrectValues).ConfigureAwait(false);
}
// Continue processing.
return true;
}
private static void SomeExpensiveCall()
{
}
private static Task<string> WaitForUserInput(IList<string> incorrectValues)
{
var taskCompletionSource = new TaskCompletionSource<string>();
Console.Write("Input Data: ");
try
{
void EventHandler(string input)
{
Input -= EventHandler;
taskCompletionSource.TrySetResult(input);
}
Input += EventHandler;
}
catch(Exception e)
{
taskCompletionSource.TrySetException(e);
}
return taskCompletionSource.Task;
}
private static IList<string> GetIncorrectValuesFromAbove()
{
return new List<string> { "Test" };
}
}
}
Of course in this example you could have just called await Console.In.ReadLineAsync() directly, but this code is to simulate an environment where you only have an event based API.
There are several ways to solve this problem, with the Control.Invoke being probably the most familiar. Here is a more TPL-ish approach. You start by declaring a UI related scheduler as a class field:
private TaskScheduler _uiScheduler;
Then initialize it:
public MyForm()
{
InitializeComponent();
_uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
}
Then you convert your synchronous LongRunning method to an asynchronous method. This means that it must return Task<bool> instead of bool. It must also have the async modifier, and by convention be named with the Async suffix:
async Task<bool> LongRunningAsync()
Finally you use the await operator in order to wait for the user's input, which will be a Task configured to run on the captured UI scheduler:
async Task<bool> LongRunningAsync()
{
// Establish some connection here.
// Do some work here.
List<Foo> incorrectValues = GetIncorrectValuesFromAbove();
if (incorrectValues.Count > 0)
{
// Here, I want to present the "incorrect values" to the user (on the UI thread)
// and let them select whether to modify a value, ignore it, or abort.
var confirmedValues = await Task.Factory.StartNew(() =>
{
return WaitForUserInput(incorrectValues);
}, default, TaskCreationOptions.None, _uiScheduler);
}
// Continue processing.
}
Starting the long running task is the same as before. The Task.Run understands async delegates, so you don't have to do something special after making the method async.
var longRunningTask = Task.Run(() => LongRunningAsync());
This should be enough, provided that you just intend to show a dialog box to the user. The Form.ShowDialog is a blocking method, so the WaitForUserInput method needs not to be asynchronous. If you had to allow the user to interact freely with the main form, the problem would be much more difficult to solve.
Another example using Invoke() and a ManualResetEvent. Let me know if you need help with the form code; setting up a constructor, using DialogResult, or creating a property to hold the "confirmedValues":
bool LongRunningTask()
{
// Establish some connection here.
// Do some work here.
List<Foo> incorrectValues = GetIncorrectValuesFromAbove();
var confirmedValues;
if (incorrectValues.Count > 0)
{
DialogResult result;
ManualResetEvent mre = new ManualResetEvent(false);
this.Invoke((MethodInvoker)delegate
{
// pass in incorrectValues to the form
// you'll have to build a constructor in it to accept them
frmSomeForm frm = new frmSomeForm(incorrectValues);
result = frm.ShowDialog();
if (result == DialogResult.OK)
{
confirmedValues = frm.confirmedValues; // get the confirmed values somehow
}
mre.Set(); // release the block below
});
mre.WaitOne(); // blocks until "mre" is set
}
// Continue processing.
}

How to make sure async task method calls gets executed synchronously [duplicate]

This question already has an answer here:
TaskScheduler with async sequential Tasks C#
(1 answer)
Closed 5 years ago.
Hi i have textbox which has text changed event. Everytime a character is inserted in textbox the text changed event is fired. The Text changed event calls a async Task method. Below is the my event and async Task method.
public Textbox_TextChangedEvent()
{
GetStocks(texboxText);
}
public async Task GetStocks(string texboxText)
{
IsBusy = true;
await Task.Run(() => { CreateCollection(texboxText); });
IsBusy = false;
}
Question
How can i make sure GetStocks method is called synchronously one after the other.
Example
Suppose user has input Ted as input text. Then i want the the async call to be completed one after other.
i.e it should call GetStocks in following order and also complete the task in following order itself.
GetStocks(T)
GetStocks(Te)
GetStocks(Ted)
To solve problems like this, we have used an AsyncLock previous projects. The AsyncLock will wait until the previous lock was released.
The AsyncLock may seem a little bit complicated first, but i hope the provided usage examples will illustrate its behaviour.
public class AsyncLock
{
private TaskCompletionSource<object> _lastSection;
public AsyncLock()
{
_lastSection = new TaskCompletionSource<object>();
_lastSection.SetResult(null);
}
public class ReleaseLock : IDisposable
{
private readonly TaskCompletionSource<object> _tcs;
public ReleaseLock(TaskCompletionSource<object> tcs)
{
_tcs = tcs;
}
public void Dispose()
{
_tcs.SetResult(null);
}
}
/// <summary>
/// Enters and locks a critical section as soon as the currently executing task has left the section.
/// The critical section is locked until the returned <see cref="IDisposable"/> gets disposed.
/// </summary>
public Task<ReleaseLock> EnterAsync()
{
var newTcs = new TaskCompletionSource<object>();
var toAwait = Interlocked.Exchange(ref _lastSection, newTcs);
return toAwait.Task.ContinueWith((_) => new ReleaseLock(newTcs), TaskContinuationOptions.ExecuteSynchronously);
}
}
You then can use await AsyncLock.EnterAsync() to wait until any previous lock was released. In the EnterAsync we queue the next Task after the current Task using ContinueWith. This means the await AsyncLock.EnterAsync() will be executed after the previous has finished.
using (await _lock.EnterAsync())
{
// ...
}
Here is an usage example:
class Program
{
private static readonly AsyncLock _lock = new AsyncLock();
private static async Task Test(int i, Task toComplete)
{
using (await _lock.EnterAsync())
{
await toComplete;
Console.WriteLine(i);
}
}
public static void Main(string[] args)
{
var tcs1 = new TaskCompletionSource<object>();
var tcs2 = new TaskCompletionSource<object>();
Task.Run(async () =>
{
var t1 = Test(1, tcs1.Task); // start first task
var t2 = Test(2, tcs2.Task); // start second task
tcs2.SetResult(null); // finish second first
tcs1.SetResult(null); // fiish last task
await Task.WhenAll(t1, t2); // will print: 1 and then 2
}).Wait();
}
}
The Test method takes will first enter the Async lock, then await the task toComplete and then write to the console.
We start two Test tasks ("1", and "2") and complete the second toComplete first. Without the AsyncLock the previous example prints: "2", "1". With the AsyncLock however the tasks are processed in the sequence they were started.
REMARKS: One last remark. This will achieve your processing order, but can be tricky sometimes. Using locks like this can easily lead to deadlocks which are hard to solve and harder to find in the first place. Use Locks very carefully.
EDIT: Here a usage example your your problem:
private readonly AsyncLock _lock = new AsyncLock();
public Textbox_TextChangedEvent()
{
GetStocks(texboxText); // every call is now "queued" after the previous one
}
public async Task GetStocks(string texboxText)
{
using(await _lock.EnterAsync())
{
IsBusy = true;
await Task.Run(() => { CreateCollection(texboxText); });
IsBusy = false;
}
}
An easy option, depending on the situation could be:
public async Task GetStocks(string texboxText)
{
Task.Run(() => {
IsBusy = true;
CreateCollection(texboxText);
IsBusy = false;
});
}

Two methods which can't run concurrently, how to write unit tests for this case, or make it testable?

Let's say I have two methods in my class MethodA and MethodB. Those methods are run in async, and I don't want that they run at the same time.
In the app, MethodA is called by the user, but MethodB is run by a Timer in a background thread.
How I see the implementation in C#ish pseudocode:
class MyClass
{
private static object _lock = new object();
public async Task MethodA()
{
lock(_lock)
{
await DoSomeStuff();
}
}
public async Task MethodB()
{
if(Monitor.IsEntered(_lock)
return;
lock(_lock)
{
await DoSomeStuff();
}
}
}
So first question is - is above approach correct? I guess that's more a question for https://codereview.stackexchange.com/.
So the second questions is - assuming that the approach is correct, how I can unit test, that MethodA waits for MethodB, and that MethodB doesn't run when MethodA is running? Or how can I refactor it so that's testable?
EDIT: accordingly to comments, changed from using flags to a lock.
Boolean flags are the obsolete way to synchronize two threads. It causes race conditions when one thread can read a value of false while other thread is updating the value to true;
Since your case it not straightforward (B shouldn't way for B to end, while A should wait), then I would change the class use a Semaphore like this:
public class MyClass
{
private SemaphoreSlim semaphore = new SemaphoreSlim(1);
public async Task MethodA()
{
await semaphore.WaitAsync();
await DoSomeStuff();
semaphore.Release();
}
public async Task MethodB()
{
bool success = await semaphore.WaitAsync(1);
if (!success)
return;
await DoSomeStuff();
await Task.Delay(TimeSpan.FromSeconds(5));
semaphore.Release();
}
}
I would consider putting all that in try..catch..finally block and release the semaphore in the finally block, but i'm trying to keep it simple while you can add that yourself.
Unit testing:
This is not straight forward to test. Taking threads into account, you might need to repeat the test multiple times to reach a case of failure. You might need to introduce an overload for method A that waits for some times, which might prove that method B is waiting for it. Here is the test. To test the case of failure, change new SemaphoreSlim(1); to new SemaphoreSlim(2); and the test would fail because MethodB would start before MethodA ends.
[TestMethod]
public async Task TestingMyClassThreadSync()
{
int repeatTimes = 100;
int counter = 0;
while (counter++ <= repeatTimes)
{
MyClass myClass = new MyClass();
Task tA = myClass.MethodA();
Task tB = myClass.MethodB();
Task finishedTask = await Task.WhenAny(tA, tB);
bool bFinishedBeforeA = finishedTask == tA;
if (bFinishedBeforeA)
Assert.Fail();
}
}
I would introduce an overload:
public async Task MethodA(long waitMilliseconds = 0)
{
await semaphore.WaitAsync();
await DoSomeStuff();
await Task.Delay(waitMilliseconds);
semaphore.Release();
}
Then Call it from unit testing as MethodA(5000);

Dissimilar behavior of async-await

I have stumbled upon a strange behavior of async-await.
Example code:
public class foo
{
public async static Task<myobj> method1()
{
var result = await method2();
return result;
}
private async static Task<myobj> method2()
{
// omitted for brevity.
}
}
public class bar
{
public void caller()
{
var result = foo.method1().Result;
pass(result);
}
}
This freezes the UI. The solution is to implement async-await on caller().
But how about this:
public class foo
{
public static myobj method1()
{
var result = method2().Result;
return result;
}
private async static Task<myobj> method2()
{
// omitted for brevity.
}
}
public class bar
{
public void caller()
{
var result = foo.method1();
pass(result);
}
}
This works freely.
What is different with private call vs. the one made to upstream method from other class?
As I mentioned in the comment, the first case is described in great details by Stephen Cleary in his blog.
The deadlock occurs at await method2(). The await continuation was posted to the UI thread's synchronization context via SynchronizationContext.Post. But the UI thread is already blocked waiting at this line: foo.method1().Result. The message pump is blocked and the continuation callback never gets pumped and invoked, deadlock.
In the second case, I don't see await anywhere. I.e., the code as you shown it doesn't do any asynchrony. I guess that's why it works.

Categories

Resources