Convert synchronous function to async function in C# - c#

I want to convert a (relatively) slow event handler to async to avoid blocking the other event subscribers. In the example below I do not want the other subscribers to the Message event to have to wait.
The only thing I can think of looks like "cheating":
client.Message += async (object sender, MessageEventArgs e) => {
await Task.Run(() => { });
logger.Info("Some info {0}", e.Message);
}
Of course I could wrap the whole logger.Info call in the Task, but I don't see why that is better. I just looks less like cheating.
My only other thought is that the handler should be left synchronous, and the Message event should only be subscribed to when latency is not critical. So I could have a second event that is only used by low latency async subscribers.
I am looking for feedback on the proper coding design here.

You can use Task.Yield if you want to attach an asynchronous handler that will be invoked after all synchronous handlers of the same event have been invoked, and you also want the asynchronous invocation to occur on the current synchronization context. For a GUI application this means that you want the handler to run on the UI thread.
client.Message += async (sender, e) =>
{
await Task.Yield();
logger.Info("Some info {0}", e.Message);
}
Don't use await Task.Run(() => { }), because it's just a verbose, idiomatic, less efficient and (possibly) less robust alternative of await Task.Yield().
If you want to attach an asynchronous handler that will run on a ThreadPool thread (instead of the current synchronization context), use Task.Run:
client.Message += async (sender, e) =>
{
await Task.Run(() => logger.Info("Some info {0}", e.Message));
}
You should only do that if you are sure that the logger object is thread-safe, supports concurrent operations, and doesn't require thread-affinity (like many COM components do).

Related

Invoke event asynchronously and catching exceptions without stopping other tasks from running

Given the following code:
public delegate Task AsyncEventHandler<in TEventArgs>(object sender, TEventArgs eventArgs);
public static Task InvokeAsync(this AsyncEventHandler eventHandler, object sender, EventArgs eventArgs)
{
if (eventHandler == null) return Task.CompletedTask;
var delegates = eventHandler.GetInvocationList().Cast<AsyncEventHandler>();
var tasks = delegates.Select(it => it.Invoke(sender, eventArgs));
return Task.WhenAll(tasks);
}
I have a test function whereby the faulty handlers should throw exceptions, and the workinghanlder should run - currently only the first FaultyHandler1 is called and no others event handlers.
private class NonGenericNotifier
{
public event AsyncEventHandler SomethingHappened;
public Task OnSomethingHappening() => SomethingHappened.InvokeAsync(this, EventArgs.Empty);
}
public async Task Multiple_Exceptions_That_Occur_During_Event_Handling_Should_Be_Propagated()
{
var isHandler1Called = false;
var isHandler2Called = false;
var isWorkingHandlerCalled = false;
var notifier = new NonGenericNotifier();
Task FaultyHandler1(object sender, EventArgs eventArgs)
{
isHandler1Called = true;
throw new InvalidOperationException();
}
Task FaultyHandler2(object sender, EventArgs eventArgs)
{
isHandler2Called = true;
throw new InvalidOperationException();
}
Task WorkingHandler(object sender, EventArgs eventArgs)
{
isWorkingHandlerCalled = true;
return Task.CompletedTask;
}
notifier.SomethingHappened += FaultyHandler1;
notifier.SomethingHappened += FaultyHandler2;
notifier.SomethingHappened += WorkingHandler;
await Should.ThrowAsync<InvalidOperationException>(async () => await notifier.OnSomethingHappening());
isHandler1Called.ShouldBe(true);
isHandler2Called.ShouldBe(true);
isWorkingHandlerCalled.ShouldBe(true);
}
Assuming a single exception can be thrown I beleive this should be an AggregateException containing an exception for each Task, and most importantly the InvokeAsync method above should bail on the first exception encountered.
I have started to create a List<Exception> within the InvokeAsync extension method, and wrap each it => it.Invoke(sender, eventArgs) with a try/catch construct and within the catch add the exception to the exception list.
However I am lost on how to collate this list of exceptions and then send on as an AggregateException.
UPDATE (FIX?)
Thanks to Artur for pointing me in the right direction. I changed the InvokeAsync extension method to the below, and it works - no longer halting on the first task. We have gone from var tasks = delegates.Select(it => it.Invoke(sender, eventArgs)); to the below using the code here:
public static Task InvokeAsync(this AsyncEventHandler eventHandler, object sender, EventArgs eventArgs)
{
if (eventHandler == null) return Task.CompletedTask;
var delegates = eventHandler.GetInvocationList().Cast<AsyncEventHandler>();
var tasks = delegates.Select(async it => await it.Invoke(sender, eventArgs));
return Task.WhenAll(tasks).WithAggregatedExceptions();
}
static Task WithAggregatedExceptions(this Task task)
{
// using AggregateException.Flatten as a bonus
return task.ContinueWith(
continuationFunction: priorTask =>
priorTask.IsFaulted &&
priorTask.Exception is AggregateException ex && (ex.InnerExceptions.Count > 1 || ex.InnerException is AggregateException) ? Task.FromException(ex.Flatten()) : priorTask,
cancellationToken: CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
scheduler: TaskScheduler.Default).Unwrap();
}
My issue is subscribers of this event, writing synchronous handlers over which I have no control - this would stop the other event handlers (sync and async) running that are attached to the same event.
I also appreciate this is the designed function of Task.WhenAll if you were mixing async and non-async handlers... if there is one reason to not write synchronous code in an async function without await Task.Yield() this is it.
Question
Can we say that wrapping the delegates.Select(async it => await it.Invoke(sender, eventArgs) with async/await allows synchronous method to run, and at worst(?) wrap twice an async method (which is the same as nesting async/await function calls) so is actually a non-issue?
Are there any side effects that have been introduced?
With the bounty looking for authorative guidance on how this would be implemented, one answer (much appreciated for contributing to the discussion) says to avoid async events, yet in other places like the discord c# client they have embraced async events (with timeout wrappers etc).
Task.WhenAll will invoke all the handlers when it reifies its parameter. It will invoke them one at a time, and then will asynchronously wait for all the tasks to complete.
The reason you were seeing the halting on the first exception was because the exception was thrown during reification. It's normal for asynchronous (Task-returning) functions to place any exceptions on the returned task. It's abnormal for asynchronous functions to throw exceptions directly.
So, this is the problematic code:
Task FaultyHandler1(object sender, EventArgs eventArgs)
{
isHandler1Called = true;
throw new InvalidOperationException();
}
One of these would be correct:
async Task FaultyHandler1(object sender, EventArgs eventArgs)
{
isHandler1Called = true;
throw new InvalidOperationException();
}
Task FaultyHandler1(object sender, EventArgs eventArgs)
{
isHandler1Called = true;
return Task.FromException(new InvalidOperationException());
}
You're seeing the odd behavior because the asynchronous handler is misbehaving (by throwing a synchronous exception).
Now, if you want to allow misbehaving asynchronous handlers, you can do that, either with an explicit try/catch or the extra async/await:
var tasks = delegates.Select(it => try { return it.Invoke(sender, eventArgs); } catch (Exception ex) { return Task.FromException(ex); });
// async/await is necessary to handle misbehaving asynchronous handlers that throw synchronous exceptions
var tasks = delegates.Select(async it => await it.Invoke(sender, eventArgs));
If you do keep the async/await approach, please do comment it, because coding constructs like that are often assumed to be spurious and may be removed by a future maintainer.
The WithAggregatedExceptions looks fine as-is, but it can be simplified if you want:
static async Task WithAggregatedExceptions(this Task task)
{
try { await task; }
catch { throw task.Exception; }
}
My issue is subscribers of this event, writing synchronous handlers over which I have no control - this would stop the other event handlers (sync and async) running that are attached to the same event.
Well, yes. Task.WhenAll reifies its collection of tasks synchronously, which invokes all the handlers one at a time.
If you want to allow synchronous handlers as well as asynchronous ones all at the same time, you can wrap the invocations in a Task.Run:
var tasks = delegates.Select(it => Task.Run(() => it.Invoke(sender, eventArgs)));
Can we say that wrapping the delegates.Select(async it => await it.Invoke(sender, eventArgs) with async/await allows synchronous method to run, and at worst(?) wrap twice an async method (which is the same as nesting async/await function calls) so is actually a non-issue?
The extra async/await for asynchronous handlers is a non-issue; it's very slightly less efficient, and appears unnecessary, so I'd say it's in danger of being removed (unless commented). It doesn't "allow synchronous methods to run"; instead, it corrects the misbehaving methods that throw exceptions directly instead of placing them on the returned Task as expected.
Are there any side effects that have been introduced?
Not really. If you do use the Task.Run approach, then all the handlers are invoked on thread pool threads and may run concurrently, which may be surprising.
one answer (much appreciated for contributing to the discussion) says to avoid async events, yet in other places like the discord c# client they have embraced async events (with timeout wrappers etc).
I am 100% in agreement with that answer.
Here's how I think about it:
The Observer pattern is a way to notify observers of state changes. The Observer pattern is a clear fit for "events" in OOP: any number of observers may subscribe to state change notifications. This is what C# events were patterned after: notifying subscribers of things. There's no mechanism for information to "flow back". While the language allows C# events with return values, it's not natural by any means. The same limitation happens with exceptions (which can be considered a kind of return): the standard handler?.Invoke pattern starts to break (stopping invocations at the first exception, etc).
As soon as you have information "flowing back" (including needing to handle exceptions, or needing to await all the handlers to complete), you're no longer in the Observer pattern, and you are no longer in the happy path of C# events.
Generally, I find most "events" of this type are usually related to a Strategy or Visitor pattern, rather than Observer. Neither Strategy nor Visitor are good fits for C# events, although they are often (sadly) implemented that way. I consider that a common design mistake (for all OOP languages).
In my opinion, the design of using C# events in an async way is not robust, and it will always behave in a slightly uncontrolled way. There are better techniques to make event processing robust.
One of the best such technologies is TPL Dataflows (https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/dataflow-task-parallel-library). This library allows you to program stream processing in a very controlled way, it helps you deal with task schedulers etc. Once you apply this successfully, all the problems in your question will be addressed.
There are obviously other alternatives out there, but I would clearly abstain from re-implementing this by using C# events....

How to return object from long running task while the task is in progress? [duplicate]

I'm completely new to C# 5's new async/await keywords and I'm interested in the best way to implement a progress event.
Now I'd prefer it if a Progress event was on the Task<> itself. I know I could just put the event in the class that contains the asynchronous method and pass some sort of state object in the event handler, but to me that seems like more of a workaround than a solution. I might also want different tasks to fire off event handlers in different objects, which sounds messy this way.
Is there a way I could do something similar to the following?:
var task = scanner.PerformScanAsync();
task.ProgressUpdate += scanner_ProgressUpdate;
return await task;
The recommended approach is described in the Task-based Asynchronous Pattern documentation, which gives each asynchronous method its own IProgress<T>:
public async Task PerformScanAsync(IProgress<MyScanProgress> progress)
{
...
if (progress != null)
progress.Report(new MyScanProgress(...));
}
Usage:
var progress = new Progress<MyScanProgress>();
progress.ProgressChanged += ...
PerformScanAsync(progress);
Notes:
By convention, the progress parameter may be null if the caller doesn't need progress reports, so be sure to check for this in your async method.
Progress reporting is itself asynchronous, so you should create a new instance of your arguments each time you call (even better, just use immutable types for your event args). You should not mutate and then re-use the same arguments object for multiple calls to Progress.
The Progress<T> type will capture the current context (e.g., UI context) on construction and will raise its ProgressChanged event in that context. So you don't have to worry about marshaling back to the UI thread before calling Report.
Simply put, Task doesn't support progress. However, there's already a conventional way of doing this, using the IProgress<T> interface. The Task-based Asynchronous Pattern basically suggests overloading your async methods (where it makes sense) to allow clients to pass in an IProgress<T> implementation. Your async method would then report progress via that.
The Windows Runtime (WinRT) API does have progress indicators built-in, in the IAsyncOperationWithProgress<TResult, TProgress> and IAsyncActionWithProgress<TProgress> types... so if you're actually writing for WinRT, those are worth looking into - but read the comments below as well.
I had to piece together this answer from several posts as I was trying to figure out how to make this work for code that is less trivial (ie events notify changes).
Let's assume you have a synchronous item processor that will announce the item number it is about to start work on. For my example I am just going to manipulate the content of the Process button, but you can easily update a progress bar etc.
private async void BtnProcess_Click(object sender, RoutedEventArgs e)
{
BtnProcess.IsEnabled = false; //prevent successive clicks
var p = new Progress<int>();
p.ProgressChanged += (senderOfProgressChanged, nextItem) =>
{ BtnProcess.Content = "Processing page " + nextItem; };
var result = await Task.Run(() =>
{
var processor = new SynchronousProcessor();
processor.ItemProcessed += (senderOfItemProcessed , e1) =>
((IProgress<int>) p).Report(e1.NextItem);
var done = processor.WorkItWorkItRealGood();
return done ;
});
BtnProcess.IsEnabled = true;
BtnProcess.Content = "Process";
}
The key part to this is closing over the Progress<> variable inside ItemProcessed subscription. This allows everything to Just works ™.
When using a Task.Run lambda I have used an Invoke Action inside of this to update a ProgressBar control. This may not be the best way but it worked in a pinch without having to restructure anything.
Invoke(new Action(() =>
{
LogProgress();
}));
Which takes it to...
private void LogProgress()
{
progressBar1.Value = Convert.ToInt32((100 * (1.0 * LinesRead / TotalLinesToRead)));
}

When do multiple awaits make sense?

I have some misunderstanding with c# async/await mechanism.
Is there any essential difference between
private async void Init()
{
await Task.Run(() => Do1());
await Task.Run(() => Do2());
}
and
private async void Init()
{
await Task.Run(() =>
{
Do1();
Do2();
});
}
The only difference I see: in the first sample Do1 and Do2 will be run in different threads while in the second sample - in the same thread. But again, what is the real benefit of it and when I should prefer the 1st approach over the second one and vice versa?
EDIT: The second case
What is the difference between
private async void Init()
{
await Task.Run(() => Do1());
Do3();
}
and
private async void Init()
{
await Task.Run(() =>
{
Do1();
Do3();
});
}
The difference is:
First example:
You queue Do1 on a threadpool thread and asynchronously wait for it to complete, then do the exact same with Do2. These may run on different threads.
You queue Do1 and Do2 to execute synchronously one after the other on the same thread pool thread.
Second example:
Queue Do1 on the threadpool and asynchronously wait for it to complete, then invoke Do3 synchronously.
This is exactly the same as the second part of the first example.
Note that when you await, you asynchronously wait for the operation to complete, hence unless the method finishes it won't execute the next line of code.
I'm assuming you're asking yourself if one is preferable to the other, and as in most cases, it depends. If you're running inside a console app, and you're going to asynchronously wait for Do1 to complete anyway, then pass both methods to the same Task.Run invocation. If you're planning on doing this in a place where synchronization matters, such as a GUI application, then any operation which needs to interact with UI controls should be invoked on the UI thread.
Another option which is more common is when you have two operations which are independent of each other and you want to start them together and wait for both to complete. This is where you'd use Task.WhenAll:
var firstDo = Task.Run(() => Do1());
var secondDo = Task.Run(() => Do2());
await Task.WhenAll(firstDo, secondDo);
Side note:
Do not use async void in asynchronous methods with no return value, that is what async Task is for. The former is only meant to allow compatibility with event handlers, where I'm assuming this isn't the case.
if Do1() and Do2() are independent from each other you should run them separately. This is even more important if they're long-running / blocking processes
on the other hand if they're related and the first one does some operations that are required by the other then it is better to run them in one thread to reduce the threading overhead. After all, you know in advance they need to run sequentially

C# Handling event in another thread, where to start Task

I need to raise an event without blocking the calling method, what is the way to do it?
1) Start a task and raise the event from within the task? :
//Body of listener function above
if (EventFound)
Task.Factory.StartNew(() =>
{
SendEvent();
});
2) Start a task from within the eventhandler:
public void OnEventRaised(....)
{
Task.Factory.StartNew(() =>
{
//Do lengthy stuff here
});
}
Does either block the calling function?
Neither of your examples blocks the caller.
In your first example the caller creates a new thread and invokes all subscribers sequentially (if there are more than one). In the second option the subscriber creates a thread, so each one will have it's own thread.
Please keep in mind that both options will crash the application if any of the event handlers fail.
You can get more relevant information from here: Raising events asynchronously
You can use Async Await keywords
http://www.codeproject.com/Tips/591586/Asynchronous-Programming-in-Csharp-using-async

Best practice for consistently cancelling Async CancellationTokenSource

So I have a combobox on my UI that on SelectionChanged it asynchronously goes off to a web service to pull back some information to be displayed on the UI (using the new C#5 async/await keywords). What I'm looking to do is cancel the current async request before sending a new one; for example if the user uses the keyboard to quickly cycle through all of the combobox items, the SelectionChanged event could fire multiple times (generating multiple async requests) before even the first async request returns.
So my async function that gets called from the combobox's SelectionChanged event looks like this:
public async Task<Connections> ConnectionsAsync()
{
return await Task.Factory.StartNew(() => Connections, _cancellationTokenSource.Token);
}
Where Connections is a property that goes off and hits the web service. So because the CancellationTokenSource cannot be reused once cancelled, I'm thinking of doing this:
public async Task<Connections> ConnectionsAsync()
{
_cancellationTokenSource.Cancel();
_cancellationTokenSource = new CancellationTokenSource();
return await Task.Factory.StartNew(() => Connections, _cancellationTokenSource.Token);
}
The problem though is that sometimes I will be calling Cancel() when there is no async command running (e.g. the first time this function is called); so if I hookup any cancellation event handlers they will get called, even before I have made an async request.
Is there anyway to check if an async request is already running? Other than me doing something like:
public async Task<Connections> ConnectionsAsync()
{
if (_runningAsyncCommand)
_cancellationTokenSource.Cancel();
_cancellationTokenSource = new CancellationTokenSource();
_runningAsyncCommand = true;
return await Task.Factory.StartNew(() => Connections, _cancellationTokenSource.Token);
_runningAsyncCommand = false;
}
I have a few async functions that all use the same CancellationTokenSource, so I would have to implement this "plumbing" in all of those functions. Is this the best approach? Or is there a better way?
Also, if I expose _cancellationTokenSource publically so that other classes can register cancellation delegates with it, what is the best way to "transfer" these delegates over to the new CancellationTokenSource, since I'm creating a new one every time?
Thanks in advance!
Looks like a match made in heaven for Reactive Extensions. Define a throttle time that has to elapse (let's say 300mS) when observing the events from the Combobox before creating the Task
Code snippet subscribing to TextBox change events, but you'll get the idea:
var input (from evt in Observable.FromEvent<EventArgs>(txt, "TextChanged")
select ((TextBox)evt.Sender).Text)
.Throttle(TimeSpan.FromSeconds(1))
.DistinctUntilChanged();
using (input.Subscribe(inp => Console.WriteLine("You wrote: " + inp)))
{
// Do stuff
}

Categories

Resources