Learning C#'s async/await/Task structure; code hangs at await? - c#

To get a sense for how C#'s threading constructs work, I've written a simple test program that performs the same task - sleeping for 3 seconds then returning an object - both synchronously and asynchronously. I've set up some stopwatches to get a better sense as to how the code is flowing.
The synchronous call is working as expected: there's a 3 sec delay between the "before sync" and "after sync" prints. However, for the async call, the program hangs indefinitely after "after async". I'm expecting "before async" and "after async" to print quickly in succession (since ExecuteAsync just returns a Task), then for "awaited async" to print three seconds later (or rather, at least three seconds later; if there was a ton of logic between ExecuteAsync and when that Task is awaited, it might be longer).
namespace TaskTest
{
class Program
{
static void Main(string[] args)
{
doStuff().Wait();
Console.WriteLine("Press any key to end");
Console.ReadKey();
}
static async Task doStuff()
{
TestClass tceOn = new TestClass(true);
Stopwatch s = Stopwatch.StartNew();
s.Checkpoint("Before sync on");
tceOn.ExecuteSync();
s.Checkpoint("After sync on");
Console.WriteLine();
s.Checkpoint("Before async on");
Task<Foo> fooTask = tceOn.ExecuteAsync();
s.Checkpoint("After async on");
Foo foo = await fooTask;
s.Checkpoint("Awaited async on");
}
}
class TestClass
{
public bool ShouldWait = false;
public TestClass(bool tce)
{
ShouldWait = tce;
}
public Task<Foo> ExecuteAsync()
{
Task<Foo> output;
RunExecute(out output, true);
return output;
}
public Foo ExecuteSync()
{
Task<Foo> dud;
return RunExecute(out dud);
}
private Foo RunExecute(out Task<Foo> task, bool async = false)
{
Foo outputFoo;
if(async)
{
task = new Task<Foo>(makeFoo);
outputFoo = null;
}
else
{
task = null;
outputFoo = makeFoo();
}
return outputFoo;
}
private Foo makeFoo()
{
if (ShouldWait)
Thread.Sleep(3000);
return new Foo();
}
}
class Foo { }
}
To clean it up a bit, I didn't paste the extension method for Stopwatch's Checkpoint() method; it just prints the number of ticks so I can get a sense for the time elapsed.
So, why isn't this code working as expected? I was hoping this would be a "simplest thing that could possibly work"-type scenario. Thanks!
Update:
Having changed my code according to Peter Duniho's first suggestion (task = Task.Run(() => makeFoo());), I'm now trying to figure out how to get this to work with a .ContinueWith() block:
private Foo RunExecute(out Task<Foo> task, bool async = false)
{
Foo outputFoo;
if(async)
{
task = Task.Run(() => makeFoo()).ContinueWith((t) => // **** error here ****
{
outputFoo = null;
});
}
else
{
task = null;
outputFoo = makeFoo();
}
return outputFoo;
}
This is giving me an implicit conversion error on the line where I made the change:
Cannot implicitly convert type 'System.Threading.Tasks.Task' to 'System.Threading.Tasks.Task<TaskTest.Foo>'
Because I'm new to how Tasks, Actions, and the like work, I'm not quite sure what the problem is/what's not matching up.

You haven't actually run any Task. So you're waiting on something that will never complete.
To fix your code exactly as it is, you can do this:
private Foo RunExecute(out Task<Foo> task, bool async = false)
{
Foo outputFoo;
if(async)
{
task = Task.Run(() => makeFoo());
outputFoo = null;
}
else
{
task = null;
outputFoo = makeFoo();
}
return outputFoo;
}
A more idiomatic way would look something like this:
private Foo RunExecute(out Task<Foo> task, bool async = false)
{
Foo outputFoo;
if(async)
{
task = makeFooAsync();
outputFoo = null;
}
else
{
task = null;
outputFoo = makeFoo();
}
return outputFoo;
}
async Task<Foo> makeFooAsync()
{
await Task.Delay(3000);
return new Foo();
}
You can even change the example so that both the synchronous and asynchronous work exactly the same (and don't require the out parameter):
private Task<Foo> RunExecute(bool async = false)
{
Foo outputFoo;
if(async)
{
return makeFooAsync();
}
else
{
return Task.FromResult(makeFoo());
}
}

To get a sense for how C#'s threading constructs work, I've written a simple test program that performs the same task - sleeping for 3 seconds then returning an object - both synchronously and asynchronously.
Your actual code is quite complex. So let's start with the "simplest possible" 3-second synchronous sleep:
class Program
{
static void Main(string[] args)
{
TestClass tceOn = new TestClass();
Stopwatch s = Stopwatch.StartNew();
s.Checkpoint("Before sync on");
tceOn.Execute();
s.Checkpoint("After sync on");
Console.WriteLine("Press any key to end");
Console.ReadKey();
}
}
class TestClass
{
public Foo Execute()
{
Thread.Sleep(3000);
return new Foo();
}
}
class Foo { }
Now, to create an asynchronous equivalent, you first start at the "leaves" - in this case, Thread.Sleep in TestClass.Execute, and work your way up. This is the natural way to convert code to be asynchronous (except in this case, we're creating the asynchronous code side-by-side instead of in-place). The first step is always to identify blocking operations (Thread.Sleep) and discover asynchronous equivalents (in this case, Task.Delay):
class TestClass
{
public async Task<Foo> ExecuteAsync()
{
await Task.Delay(3000);
return new Foo();
}
public Foo Execute()
{
Thread.Sleep(3000);
return new Foo();
}
}
Note the similarities between the two methods. Also note that there is no need for Task.Run. This is the case for all naturally-asynchronous code.
At this point, you're ready to add the asynchronous test. Since Main can't be async, this is the point at which you need to move the test code to another method:
class Program
{
static void Main(string[] args)
{
MainAsync().Wait();
Console.WriteLine("Press any key to end");
Console.ReadKey();
}
static async Task MainAsync()
{
TestClass tceOn = new TestClass();
Stopwatch s = Stopwatch.StartNew();
s.Checkpoint("Before sync on");
tceOn.Execute();
s.Checkpoint("After sync on");
s.Checkpoint("Before async on");
Task<Foo> fooTask = tceOn.ExecuteAsync();
s.Checkpoint("After async on");
Foo foo = await fooTask;
s.Checkpoint("Awaited async on");
}
}
For your final question regarding ContinueWith, the answer is "don't use ContinueWith; use await instead".

Related

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.
}

Waiting for all jobs to be finished with async await

I'm trying to understand the usage of async-await in C#5. If I have 2 jobs started in a method, is there a best way to wait for their completion in C#5+ ? I've done the example below but I fail to see what the async await keywork brings here besides free documentation with async keyword.
I made the following example, I want "FINISHED !" to be printed last. It is not the case however. What did I miss ? How can I make the async method wait until all jobs are finished ? Is there a point using async-await here ? I could just do Task.WaitAll with a non-async method here. I don't really understand what async brings in case you want to wait.
class Program
{
static void Main(string[] args)
{
var fooWorker = new FooWorker();
var barWorker = new BarWorker();
var test = new Class1(fooWorker, barWorker);
test.SomeWork();
Console.ReadLine();
}
}
public class Foo
{
public Foo(string bar) => Bar = bar;
public string Bar { get; }
}
public class Class1
{
private IEnumerable<Foo> _foos;
private readonly FooWorker _fooWorker;
private readonly BarWorker _barWorker;
public Class1(FooWorker fooWorker, BarWorker barWorker)
{
_fooWorker = fooWorker;
_barWorker = barWorker;
}
public void SomeWork()
{
_foos = ProduceManyFoo();
MoreWork();
Console.WriteLine("FINISHED !");
}
private async void MoreWork()
{
if (_foos == null || !_foos.Any()) return;
var fooList = _foos.ToList();
Task fooWorkingTask = _fooWorker.Work(fooList);
Task barWorkingTask = _barWorker.Work(fooList);
await Task.WhenAll(fooWorkingTask, barWorkingTask);
}
private IEnumerable<Foo> ProduceManyFoo()
{
int i = 0;
if (++i < 100) yield return new Foo(DateTime.Now.ToString(CultureInfo.InvariantCulture));
}
}
public abstract class AWorker
{
protected virtual void DoStuff(IEnumerable<Foo> foos)
{
foreach (var foo in foos)
{
Console.WriteLine(foo.Bar);
}
}
public Task Work(IEnumerable<Foo> foos) => Task.Run(() => DoStuff(foos));
}
public class FooWorker : AWorker { }
public class BarWorker : AWorker { }
You are firing off tasks and just forgetting them, while the thread continues running. This fixes it.
Main:
static async Task Main(string[] args)
{
var fooWorker = new FooWorker();
var barWorker = new BarWorker();
var test = new Class1(fooWorker, barWorker);
await test.SomeWork();
Console.ReadLine();
}
SomeWork:
public async Task SomeWork()
{
_foos = ProduceManyFoo();
await MoreWork();
Console.WriteLine("FINISHED !");
}
MoreWork signature change:
private async Task MoreWork()
The obvious code smell which should help make the problem clear is using async void. Unless required this should always be avoided.
When using async and await you'll usually want to chain the await calls to the top-level (in this case Main).
await is non-blocking, so anything that calls an async method should really care about the Task being returned.

How to return on Task<int>?

I've this code:
static void Main(string[] args)
{
// start import process
Task<int> task = StartImportProcess();
task.Wait();
// check result
// process finished
Console.ReadKey();
}
static async Task<int> StartImportProcess()
{
int result = 0;
result = await ImportCustomers();
// some other async/await operations
return result;
}
static Task<int> ImportCustomers()
{
// some heavy operations
Thread.Sleep(1000);
return 1; // <<< what should I return?
}
Using Task and async/await. I'd like to return an int as result of the task. Which object whould I return? return 1; won't work.
You should use Task.FromResult, (and don't use Thread.Sleep from a Task):
static async Task<int> ImportCustomers()
{
// some heavy operations
await Task.Delay(1000);
// Already awaited, so we can return the result as-is.
return 1;
// Or: if not already awaited anything,
// and also with non-async tasks, use:
return Task.FromResult(1);
}

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);

Is it safe to pass Task as method parameter?

Consider the following code:
public class Program {
static void Main(string[] args) {
Generate();
}
static void Generate() {
Task t = null;
t = Task.Run(() => {
MyClass myClass = new MyClass();
myClass.ContinueTask(t);
});
Console.ReadLine();
}
}
public class MyClass {
public void ContinueTask(Task t) {
t.ContinueWith(x => {
Console.WriteLine("Continue here...");
});
}
}
Is it safe to pass t as parameter as so or is it better to directly start a new task inside MyClass?
This is unsafe because t might not be assigned at the point where it is used. In fact this is a data race.
Even if you fixed that it would be bad architecture. Why does ContinueTask need to know that it is continuing with something. This is a not a concern that should be located here. ContinueTask should perform it's work assuming that its antecedent has completed already.
It's hard to tell what you are trying to accomplish. What's wrong with sequencing your code like this:?
static async Task Generate() {
var t = Task.Run(() => {
//... other code ...
});
MyClass myClass = new MyClass();
await t;
myClass.ContinueTask();
Console.ReadLine();
}
await is perfect for sequencing tasks.
reusing the Task object
What do you mean by that? A task cannot be reused. It cannot run twice. All that your ContinueWith does is logically wait for the antecedent and then run the lambda. Here, the task serves as an event basically.
ContinueWith does not modify the task it is being called on. It creates a new task.
I've reduced your code down to this example:
public Task<int> Parse()
{
Task<int> t = null;
t = Task.Run(() => this.Read(t));
return t;
}
public Task<int> Read(Task<int> t)
{
return t.ContinueWith(v => 42);
}
I think that has the same underlying structure.
This causes a dead-lock. I suspect your code does too. So I think it's unsafe.

Categories

Resources