Why method has to be async task to catch exceptions - c#

I've got method which I want to run asynchronously:
public async Task Send(MemoryMapModel memoryMap, SerialPort serialPort, ProgressBar progressBar, Settings settings)
{
SendFrames(memoryMap, serialPort, progressBar, _token.Token, settings);
}
And I use it like this by Task.Run():
await Task.Run(async () => await _rtuLogic.Send(memoryMap, serialPort, pbProgressBar, settings).ConfigureAwait(false));
Method "Send" throws exceptions which I want to catch, but to do that, it has to be async Task, but there are no awaitable methods and VS wants me not to use async keyword.
Why can't I catch exceptions from Task.Run(() => void) but it do works for Task.Run(async () => async Task), though there are no awaitable methods?
EDIT:
Also when I tried
Task.Factory.StartNew(() => { _rtuLogic.SendAsync(memoryMap, serialPort, pbProgressBar, settings); });
I can't catch and handle exceptions.
If I don't use Task.Run(...) Send doesn't run asynchronously and freezes GUI.

Some people may see it as a bit outdated now we have async, but you seem to be throwing async/await in everywhere and hoping it'll solve your problem.1
So I'd suggest ditching this attempt and look at using BackgroundWorker instead. It lets you clearly separate the bits that should happen "elsewhere" from the bits that still need to access the UI and should help avoid blocking it.
Task.Run should generally be avoided unless you have CPU bound work that you want to move off the current thread.
If you do want to go async/await then ideally you find the async variant of SendFrames and use that instead. But if that's not available/written yet then don't try to pretend that it's async.
1A now deleted answer linked to this answer by Stephen Cleary which in turn links off to other articles/posts about async, which I'd suggest you should try to ready all of them and other Stephen Cleary blog posts too (There is no thread should always be a recommended read)

Related

When is it asynchronous and when is synchronous

Having read a /lot/ of documentation on the async await pattern I thought I had a pretty good handle on the pattern. I read all about async all the way then read another article that mentions 'if it runs in under 50 milliseconds don't async it'. It seems there is conflicting information and/or opinions and I have managed to just confuse myself. I have also read that Task.Yield() will force an async decorated method to run asynchronously.
Given the following code:
static async Task MethodA() {
await MethodB().ConfigureAwait(false);
}
static async Task MethodB() {
await Task.Yield();
MethodC();
}
static void MethodC() {
// do some synchronous stuff
}
static async Task Main(string[] args) {
var task1 = Task.Run(() => MethodA().ConfigureAwait(false));
var task2 = Task.Run(() => MethodB().ConfigureAwait(false));
await Task.WhenAll(new List<Task>() { task1, task2 });
}
Will MethodC run synchronously or asynchronously, I assumed asynchronously as it was called from an asynchronous method. Also, is Task.Yield necessary at all?
To be honest this is doing my head in, every article I have read delves deeper and deeper into the async await pattern with the whys and wherefores and is just adding more complexity to the question. Just looking for a simple answer.
Will MethodC run synchronously or asynchronously
Synchronously. It has a synchronous signature, so it will always run synchronously.
I assumed asynchronously as it was called from an asynchronous method
The context from which it is called is irrelevant to how MethodC will run.
is Task.Yield necessary at all
Well it will force MethodB to yield a Task before MethodC runs, but this will be incomplete until MethodC finishes, and because MethodC is synchronous (does not release the thread) it achieves nothing useful.
Just looking for a simple answer
async bubbles up the call stack, and because you are not consuming an async method here (MethodC is synchronous) you should not be using async at all.
This answer contains general info and advices, and it's not focused on the code that you posted.
Being confused while learning async-await is OK. Getting a perfect understanding of async-await without going through a confusion phase is practically almost impossible IMHO.
The await Task.Yield(), await Task.Delay(1), await Task.Run(() => { }), and .ConfigureAwait(false) are dirty hacks that people sometimes use out of frustration that an explicit way to switch imperatively to the ThreadPool context does not exist (in the standard libraries). A SwitchTo method existed in some pre-prelease .NET version, then it was removed for technical reasons, then the technical reasons were eliminated, reintroducing the method never became a high enough priority, and so it didn't happen. It may happen in the future, but don't hold your breath. It is currently available in the Microsoft.VisualStudio.Threading package, if you want it.
You don't need any of these hacks to write async-await code successfully. If you want to offload work to the ThreadPool, there is the Task.Run method that does the job perfectly.
Offloading work to the ThreadPool should be done at the "application code" level, not at the "library code" level. You can read this article to understand why exposing asynchronous wrappers for synchronous methods is not a good idea.

Is it just plain wrong to return Task instead of Task<T>?

The task API feels sort of like a pit of failure, given how every possible thing I could do with it comes with more DON'T than DO. But I'm trying to use it more, and I'm confused about the entire issue of async void.
My problem happens in a place where my application's used a local data file forever, and because it was fast synchronous calls were used. Now some remote sources are an option, and they have enough latency I'm switching it all to be asynchronous.
So I've got a method that maybe looks like this:
void InitializeData() {
SomeProperty = _dataSource.Load(...);
}
The naive thing I want to do for low-friction is:
Task InitializeDataAsync() {
return Task.Run(() => {
SomeProperty = _dataSource.Load(...);
});
}
But there are SO many articles about how terrible it is to use async void, and they seem to blur with discussion of returning a Task. So is my best option really to write it like:
Task<DataType> FetchDataAsync() {
return _dataSource.LoadAsync(...);
}
...then hunt down all the callers and make them comply?
I feel like the argument people make is that async void is bad because of the different behavior of async Task and the dreaded UnobservedTaskException when you use await. In this situation, I'm very unlikely to ever be using await. Or if I do use await, it's always going to have a try/catch around it because we're already paranoid about UnobservedTaskException.
So:
Is "Don't use async void" the same thing as "Don't use Task?
If you don't use await, does it mitigate that?
If you do use await, does always wrapping it with a try/catch mitigate the issue?
async void is not the same as returning a Task. The problem with async void is there is no way to observe task exceptions (other then the global exception handler), and no way to wait for the task to complete (you actually can't await an async void method because there is nothing to await), this is why it should be avoided.
Returning Task does not have these problems, if you await it you know when it completes and you will get exceptions where you await so returning a Task is perfectly acceptable.
It looks like you're just confused. The await/async API is incredibly simple. The only confusing part is understanding the difference between await/async API and the Task API. I won't go into great detail about this as the Stephen Cleary's blog clearly covers this, but here is the important excerpt:
To reiterate a sentence from my last post, use Task.Run to call CPU-bound methods (from GUI threads). Do not use it just to “provide something awaitable for my async method to use”.
next...
The naive thing I want to do for low-friction is:
Task InitializeDataAsync() {
return Task.Run(() => {
SomeProperty = _dataSource.Load(...);
});
}
This is a clear case of offloading Sync code into a Async wrapper which doesn't really do any good.
But there are SO many articles about how terrible it is to use async void,
This is clearly not a async void method. This is a non-async Task returning method. Here is an async void method:
async void InitializeDataAsync() {
await Task.Run(() => {
SomeProperty = _dataSource.Load(...);
});
}
they seem to blur with discussion of returning a Task.
I've not read anything that blurs this information. It's pretty simple; if you have an async method, always return Task or Task<T> (except as stated below). The difference between using these two (Task or Task<T>) is purely design/architecture.
So is my best option really to write it like:
Best is really an opinion here. Both of these work and don't forget async/wait
async Task<DataType> FetchDataAsync() {
return await _dataSource.LoadAsync(...);
}
async Task FetchDataAsync() {
_data = await _dataSource.LoadAsync(...);
}
I feel like the argument people make is that async void is bad because of the different behavior of async Task and the dreaded UnobservedTaskException when you use await.
The most important difference is how exceptions are handled:
Excerpt:
Async void methods have different error-handling semantics. When an exception is thrown out of an async Task or async Task method, that exception is captured and placed on the Task object. With async void methods, there is no Task object, so any exceptions thrown out of an async void method will be raised directly on the SynchronizationContext that was active when the async void method started.
So
Or if I do use await, it's always going to have a try/catch around it because we're already paranoid about UnobservedTaskException.
This means that you can't catch an exception by try/catch around async void. That is a huge problem!
Is "Don't use async void" the same thing as "Don't use Task?"
Well this is apples and oranges. Yes: don't use async void unless you're using them for async event handlers.
Don't use Task's unless they are CPU bound or you're using a Framework call (or you've correctly wrapped your own method which uses IO Completion Ports).
If you don't use await, does it mitigate that?
Hopefully by now you understand that await/async is different from a Task, and what you're trying to do is write all await/async code.
If you do use await, does always wrapping it with a try/catch mitigate the issue?
Depends, as stated above.

is using an an `async` lambda with `Task.Run()` redundant?

I just came across some code like:
var task = Task.Run(async () => { await Foo.StartAsync(); });
task.Wait();
(No, I don't know the inner-workings of Foo.StartAsync()). My initial reaction would be get rid of async/await and rewrite as:
var task = Foo.StartAsync();
task.Wait();
Would that be correct, or not (again, knowing nothing at all about Foo.StartAsync()). This answer to What difference does it make - running an 'async' action delegate with a Task.Run ... seems to indicate there may be cases when it might make sense, but it also says "To tell the truth, I haven't seen that many scenarios ..."
Normally, the intended usage for Task.Run is to execute CPU-bound code on a non-UI thread. As such, it would be quite rare for it to be used with an async delegate, but it is possible (e.g., for code that has both asynchronous and CPU-bound portions).
However, that's the intended usage. I think in your example:
var task = Task.Run(async () => { await Foo.StartAsync(); });
task.Wait();
It's far more likely that the original author is attempting to synchronously block on asynchronous code, and is (ab)using Task.Run to avoid deadlocks common in that situation (as I describe on my blog).
In essence, it looks like the "thread pool hack" that I describe in my article on brownfield asynchronous code.
The best solution is to not use Task.Run or Wait:
await Foo.StartAsync();
This will cause async to grow through your code base, which is the best approach, but may cause an unacceptable amount of work for your developers right now. This is presumably why your predecessor used Task.Run(..).Wait().
Mostly yes.
Using Task.Run like this is mostly used by people who don't understand how to execute an async method.
However, there is a difference. Using Task.Run means starting the async method on a ThreadPool thread.
This can be useful when the async method's synchronous part (the part before the first await) is substantial and the caller wants to make sure that method isn't blocking.
This can also be used to "get out of" the current context, for example where there isn't a SynchronizationContext.
It's worth noting that your method has to be marked async to be able to use the await keyword.
The code as written seems to be a workaround for running asynchronous code in a synchronous context. While I wouldn't say you should never ever do this, using async methods is preferable in almost every scenario.
// use this only when running Tasks in a synchronous method
// use async instead whenever possible
var task = Task.Run(async () => await Foo.StartAsync());
task.Wait();
Async methods, like your example of Foo.StartAsync(), should always return a Task object. This means that using Task.Run() to create another task is usually redundant in an async method. The task returned by the async method can simply be awaited by using the await keyword. The only reason you should use Task.Run() is when you are performing CPU-bound work that needs to be performed on a separate thread. The task returned by the async method can simply be awaited by using the await keyword. You can read more in depth details in Microsoft's guide to async programming.
In an async method, your code can be as simple as:
await Foo.StartAsync();
If you want to perform some other work while the task is running, you can assign the function to a variable and await the result (task completion) later.
For example:
var task = Foo.StartAsync();
// do some other work before waiting for task to finish
Bar();
Baz();
// now wait for the task to finish executing
await task;
With CPU-bound work that needs to be run on a separate thread, you can use Task.Run(), but you await the result instead of using the thread blocking Task.Wait():
var task = Task.Run(async () => await Foo.StartAsync());
// do some other work before waiting for task to finish
Bar();
Baz();
// now wait for the task to finish executing
await task;

Is it possible to use a CancellationToken with ExecuteReader?

The new async ExecuteReaderAsync takes a CancellationToken. Is there any way to cancel the old synchronous ExecuteReader?
In our case, all the data operations are synchronous on a background thread, so await is not an option. I don't want to start a second thread- Task.Run(() => command.ExecuteReaderAsync(token)).Result seems a waste just to be able to cancel from the UI thread.
Performance tests showed almost 2x performance benefit to a using a dedicated synchronous data-reading thread, compared to using the Begin or Async APIs with their thread pool continuations. (Since tens of millions of rows will be loaded in as many seconds, we prefer performance in this case.)
An extension method for convenient token passing:
public static SqlDataReader ExecuteReader(this SqlCommand command, CommandBehavior commandBehavior, CancellationToken cancellationToken)
{
try
{
using (cancellationToken.Register(command.Cancel))
return command.ExecuteReader(commandBehavior);
}
catch (SqlException) when (cancellationToken.IsCancellationRequested)
{
throw new OperationCanceledException(cancellationToken);
}
}
I did some spelunking with Reflector decompilation. The Begin and Async versions are both very frugal, but are both fully based on the TPL async. Because of that, there is thread pool dispatching for continuations on both.
This extension method has no threading overhead. The thread that calls Cancel on the token source will also call command.Cancel which will immediately cause a SqlException in the data thread.
I can't respond authoritatively to your edit but there's a few things you should know about your initial question:
Task.Run( ... ).Result is blocking; that syntax is a little misleading.
await Task.Run( () => command.ExecuteReaderAsync(token)); will block only the remainder of the executing method; allowing the rest to be treated as a callback.
await Task.Run( () => command.ExecuteReaderAsync(token), token); works as above but allows the task parallel library to honor to your cancellation token as well.
As to the main question, this msdn article suggests that ExecuteReaderAsync() is truly honoring that cancellationToken. Bear in mind there are a couple of methods in the framework that will not actually do that.

When would I use Task.Yield()?

I'm using async/await and Task a lot but have never been using Task.Yield() and to be honest even with all the explanations I do not understand why I would need this method.
Can somebody give a good example where Yield() is required?
When you use async/await, there is no guarantee that the method you call when you do await FooAsync() will actually run asynchronously. The internal implementation is free to return using a completely synchronous path.
If you're making an API where it's critical that you don't block and you run some code asynchronously, and there's a chance that the called method will run synchronously (effectively blocking), using await Task.Yield() will force your method to be asynchronous, and return control at that point. The rest of the code will execute at a later time (at which point, it still may run synchronously) on the current context.
This can also be useful if you make an asynchronous method that requires some "long running" initialization, ie:
private async void button_Click(object sender, EventArgs e)
{
await Task.Yield(); // Make us async right away
var data = ExecuteFooOnUIThread(); // This will run on the UI thread at some point later
await UseDataAsync(data);
}
Without the Task.Yield() call, the method will execute synchronously all the way up to the first call to await.
Internally, await Task.Yield() simply queues the continuation on either the current synchronization context or on a random pool thread, if SynchronizationContext.Current is null.
It is efficiently implemented as custom awaiter. A less efficient code producing the identical effect might be as simple as this:
var tcs = new TaskCompletionSource<bool>();
var sc = SynchronizationContext.Current;
if (sc != null)
sc.Post(_ => tcs.SetResult(true), null);
else
ThreadPool.QueueUserWorkItem(_ => tcs.SetResult(true));
await tcs.Task;
Task.Yield() can be used as a short-cut for some weird execution flow alterations. For example:
async Task DoDialogAsync()
{
var dialog = new Form();
Func<Task> showAsync = async () =>
{
await Task.Yield();
dialog.ShowDialog();
}
var dialogTask = showAsync();
await Task.Yield();
// now we're on the dialog's nested message loop started by dialog.ShowDialog
MessageBox.Show("The dialog is visible, click OK to close");
dialog.Close();
await dialogTask;
// we're back to the main message loop
}
That said, I can't think of any case where Task.Yield() cannot be replaced with Task.Factory.StartNew w/ proper task scheduler.
See also:
"await Task.Yield()" and its alternatives
Task.Yield - real usages?
One use of Task.Yield() is to prevent a stack overflow when doing async recursion. Task.Yield() prevents syncronous continuation. Note, however, that this can cause an OutOfMemory exception (as noted by Triynko). Endless recursion is still not safe and you're probably better off rewriting the recursion as a loop.
private static void Main()
{
RecursiveMethod().Wait();
}
private static async Task RecursiveMethod()
{
await Task.Delay(1);
//await Task.Yield(); // Uncomment this line to prevent stackoverlfow.
await RecursiveMethod();
}
Task.Yield() is like a counterpart of Thread.Yield() in async-await but with much more specific conditions. How many times do you even need Thread.Yield()? I will answer the title "when would you use Task.Yield()" broadly first. You would when the following conditions are fulfilled:
want to return the control to the async context (suggesting the task scheduler to execute other tasks in the queue first)
need to continue in the async context
prefer to continue immediately when the task scheduler is free
do not want to be cancelled
prefer shorter code
The term "async context" here means "SynchronizationContext first then TaskScheduler". It was used by Stephen Cleary.
Task.Yield() is approximately doing this (many posts get it slightly wrong here and there):
await Task.Factory.StartNew(
() => {},
CancellationToken.None,
TaskCreationOptions.PreferFairness,
SynchronizationContext.Current != null?
TaskScheduler.FromCurrentSynchronizationContext():
TaskScheduler.Current);
If any one of the conditions is broken, you need to use other alternatives instead.
If the continuation of a task should be in Task.DefaultScheduler, you normally use ConfigureAwait(false). On the contrary, Task.Yield() gives you an awaitable not having ConfigureAwait(bool). You need to use the approximated code with TaskScheduler.Default.
If Task.Yield() obstructs the queue, you need to restructure your code instead as explained by noseratio.
If you need the continuation to happen much later, say, in the order of millisecond, you would use Task.Delay.
If you want the task to be cancellable in the queue but do not want to check the cancellation token nor throw an exception yourself, you need to use the approximated code with a cancellation token.
Task.Yield() is so niche and easily dodged. I only have one imaginary example by mixing my experience. It is to solve an async dining philosopher problem constrained by a custom scheduler. In my multi-thread helper library InSync, it supports unordered acquisitions of async locks. It enqueues an async acquisition if the current one failed. The code is here. It needs ConfigureAwait(false) as a general purpose library so I need to use Task.Factory.StartNew. In a closed source project, my program needs to execute significant synchronous code mixed with async code with
a high thread priority for semi-realtime work
a low thread priority for some background work
a normal thread priority for UI
Thus, I need a custom scheduler. I could easily imagine some poor developers somehow need to mix sync and async code together with some special schedulers in a parallel universe (one universe probably does not contain such developers); but why wouldn't they just use the more robust approximated code so they do not need to write a lengthy comment to explain why and what it does?
Task.Yield() may be used in mock implementations of async methods.

Categories

Resources