Should we use ConfigureAwait(false) in libraries that call async callbacks? - c#

There are lots of guidelines for when to use ConfigureAwait(false), when using await/async in C#.
It seems the general recommendation is to use ConfigureAwait(false) in library code, as it rarely depends on the synchronization context.
However, assume we are writing some very generic utility code, which takes a function as input. A simple example could be the following (incomplete) functional combinators, to make simple task-based operations easier:
Map:
public static async Task<TResult> Map<T, TResult>(this Task<T> task, Func<T, TResult> mapping)
{
return mapping(await task);
}
FlatMap:
public static async Task<TResult> FlatMap<T, TResult>(this Task<T> task, Func<T, Task<TResult>> mapping)
{
return await mapping(await task);
}
The question is, should we use ConfigureAwait(false) in this case? I am unsure how the context capture works wrt. closures.
On one hand, if the combinators are used in a functional way, the synchronization context should not be necessary. On the other hand, people might misuse the API, and do context dependent stuff in the provided functions.
One option would be to have separate methods for each scenario (Map and MapWithContextCapture or something), but it feels ugly.
Another option might be to add the option to map/flatmap from and into a ConfiguredTaskAwaitable<T>, but as awaitables don't have to implement an interface this would result in a lot of redundant code, and in my opinion be even worse.
Is there a good way to switch the responsibility to the caller, such that the implemented library doesn't need to make any assumptions on whether or not the context is needed in the provided mapping-functions?
Or is it simply a fact, that async methods don't compose too well, without various assumptions?
EDIT
Just to clarify a few things:
The problem does exist. When you execute the "callback" inside the utility function, the addition of ConfigureAwait(false) will result in a null sync. context.
The main question is how we should tackle the situation. Should we ignore the fact that someone might want to use the sync. context, or is there a good way to shift the responsibility out to the caller, apart from adding some overload, flag or the like?
As a few answers mention, it would be possible to add a bool-flag to the method, but as I see it, this is not too pretty either, as it will have to be propagated all the way through the API's (as there are more "utility" functions, depending on the ones shown above).

When you say await task.ConfigureAwait(false) you transition to the thread-pool causing mapping to run under a null context as opposed to running under the previous context. That can cause different behavior. So if the caller wrote:
await Map(0, i => { myTextBox.Text = i.ToString(); return 0; }); //contrived...
Then this would crash under the following Map implementation:
var result = await task.ConfigureAwait(false);
return await mapper(result);
But not here:
var result = await task/*.ConfigureAwait(false)*/;
...
Even more hideous:
var result = await task.ConfigureAwait(new Random().Next() % 2 == 0);
...
Flip a coin about the synchronization context! This looks funny but it is not as absurd as it seems. A more realistic example would be:
var result =
someConfigFlag ? await GetSomeValue<T>() :
await task.ConfigureAwait(false);
So depending on some external state the synchronization context that the rest of the method runs under can change.
This also can happen with very simple code such as:
await someTask.ConfigureAwait(false);
If someTask is already completed at the point of awaiting it there will be no switch of context (this is good for performance reasons). If a switch is necessary then the rest of the method will resume on the thread pool.
This non-determinism a weakness of the design of await. It's a trade-off in the name of performance.
The most vexing issue here is that when calling the API is is not clear what happens. This is confusing and causes bugs.
What to do?
Alternative 1: You can argue that it is best to ensure deterministic behavior by always using task.ConfigureAwait(false).
The lambda must make sure that it runs under the right context:
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext;
Map(..., async x => await Task.Factory.StartNew(
() => { /*access UI*/ },
CancellationToken.None, TaskCreationOptions.None, uiScheduler));
It's probably best to hide some of this in a utility method.
Alternative 2: You can also argue that the Map function should be agnostic to the synchronization context. It should just leave it alone. The context will then flow into the lambda. Of course, the mere presence of a synchronization context might alter the behavior of Map (not in this particular case but in general). So Map has to be designed to handle that.
Alternative 3: You can inject a boolean parameter into Map that specifies whether to flow the context or not. That would make the behavior explicit. This is sound API design but it clutters the API. It seems inappropriate to concern a basic API such as Map with synchronization context issues.
Which route to take? I think it depends on the concrete case. For example, if Map is a UI helper function it makes sense to flow the context. If it is a library function (such as a retry helper) I'm not sure. I can see all alternatives make sense. Normally, it is recommended to apply ConfigureAwait(false) in all library code. Should we make an exception in those cases where we call user callbacks? What if we have already left the right context e.g.:
void LibraryFunctionAsync(Func<Task> callback)
{
await SomethingAsync().ConfigureAwait(false); //Drops the context (non-deterministically)
await callback(); //Cannot flow context.
}
So unfortunately, there is no easy answer.

The question is, should we use ConfigureAwait(false) in this case?
Yes, you should. If the inner Task being awaited is context aware and does use a given synchronization context, it would still be able to capture it even if whoever is invoking it is using ConfigureAwait(false). Don't forget that when disregarding the context, you're doing so in the higher level call, not inside the provided delegate. The delegate being executed inside the Task, if needed, will need to be context aware.
You, the invoker, have no interest in the context, so it's absolutely fine to invoke it with ConfigureAwait(false). This effectively does what you want, it leaves the choice of whether the internal delegate will include the sync context up to the caller of your Map method.
Edit:
The important thing to note is that once you use ConfigureAwait(false), any method execution after that would be on on an arbitrary threadpool thread.
A good idea suggested by #i3arnon would be to accept an optional bool flag indicating whether context is needed or not. Although a bit ugly, would be a nice work around.

I think the real issue here comes from the fact that you are adding operations to Task while you actually operate on the result of it.
There's no real reason to duplicate these operations for the task as a container instead of keeping them on the task result.
That way you don't need to decide how to await this task in a utility method as that decision stays in the consumer code.
If Map is instead implemented as follows:
public static TResult Map<T, TResult>(this T value, Func<T, TResult> mapping)
{
return mapping(value);
}
You can easily use it with or without Task.ConfigureAwait accordingly:
var result = await task.ConfigureAwait(false)
var mapped = result.Map(result => Foo(result));
Map here is just an example. The point is what are you manipulating here. If you are manipulating the task, you shouldn't await it and pass the result to a consumer delegate, you can simply add some async logic and your caller can choose whether to use Task.ConfigureAwait or not. If you are operating on the result you don't have a task to worry about.
You can pass a boolean to each of these methods to signify whether you want to continue on the captured context or not (or even more robustly pass an options enum flags to support other await configurations). But that violates separation of concerns, as this doesn't have anything to do with Map (or its equivalent).

Related

Chaining arbitrary number of tasks together in C#.NET

What I have
I have a set of asynchronous processing methods, similar to:
public class AsyncProcessor<T>
{
//...rest of members, etc.
public Task Process(T input)
{
//Some special processing, most likely inside a Task, so
//maybe spawn a new Task, etc.
Task task = Task.Run(/* maybe private method that does the processing*/);
return task;
}
}
What I want
I would like to chain them all together, to execute in sequential order.
What I tried
I have tried to do the following:
public class CompositeAsyncProcessor<T>
{
private readonly IEnumerable<AsyncProcessor<T>> m_processors;
//Constructor receives the IEnumerable<AsyncProcessor<T>> and
//stores it in the field above.
public Task ProcessInput(T input)
{
Task chainedTask = Task.CompletedTask;
foreach (AsyncProcessor<T> processor in m_processors)
{
chainedTask = chainedTask.ContinueWith(t => processor.Process(input));
}
return chainedTask;
}
}
What went wrong
However, tasks do not run in order because, from what I have understood, inside the call to ContinueWith, the processor.Process(input) call is performed immediately and the method returns independently of the status of the returned task. Therefore, all processing Tasks still begin almost simultaneously.
My question
My question is whether there is something elegant that I can do to chain the tasks in order (i.e. without execution overlap). Could I achieve this using the following statement, (I am struggling a bit with the details), for example?
chainedTask = chainedTask.ContinueWith(async t => await processor.Process(input));
Also, how would I do this without using async/await, only ContinueWith?
Why would I want to do this?
Because my Processor objects have access to, and request things from "thread-unsafe" resources. Also, I cannot just await all the methods because I have no idea about how many they are, so I cannot just write down the necessary lines of code.
What do I mean by thread-unsafe? A specific problem
Because I may be using the term incorrectly, an illustration is a bit better to explain this bit. Among the "resources" used by my Processor objects, all of them have access to an object such as the following:
public interface IRepository
{
void Add(object obj);
bool Remove(object obj);
IEnumerable<object> Items { get; }
}
The implementation currently used is relatively naive. So some Processor objects add things, while others retrieve the Items for inspection. Naturally, one of the exceptions I get all too often is:
InvalidOperationException: Collection was modified, enumeration
operation may not execute.
I could spend some time locking access and pre-running the enumerations. However, this was the second option I would get down to, while my first thought was to just make the processes run sequentially.
Why must I use Tasks?
While I have full control in this case, I could say that for the purposes of the question, I might not be able to change the base implementation, so what would happen if I were stuck with Tasks? Furthermore, the operations actually do represent relatively time-consuming CPU-bound operations plus I am trying to achieve a responsive user interface so I needed to unload some burden to asynchronous operations. While being useful and, in most of my use-cases, not having the necessity to chain multiple of them, rather a single one each time (or a couple, but always specific and of a specific count, so I was able to hook them together without iterations and async/await), one of the use-cases finally necessitated chaining an unknown number of Tasks together.
How I deal with this currently
The way I am dealing with this currently is to append a call to Wait() inside the ContinueWith call, i.e.:
foreach (AsyncProcessor<T> processor in m_processors)
{
chainedTask = chainedTask.ContinueWith(t => processor.Process(input).Wait());
}
I would appreciate any idea on how I should do this, or how I could do it more elegantly (or, "async-properly", so to speak). Also, I would like to know how I can do this without async/await.
Why my question is different from this question, which did not answer my question entirely.
Because the linked question has two tasks, so the solution is to simply write the two lines required, while I have an arbitrary (and unknown) number of tasks, so I need an suitable iteration. Also, my method is not async. I now understand (from the single briefly available answer, which was deleted) that I could do it fairly easily if I changed my method to async and await each processor's Task method, but I still wish to know how this could be achieved without async/await syntax.
Why my question is not a duplicate of the other linked questions
Because none of them explains how to chain correctly using ContinueWith and I am interested in a solution that utilizes ContinueWith and does not make use of the async/await pattern. I know this pattern may be the preferable solution, I want to understand how to (if possible) make arbitrary chaining using ContinueWith calls properly. I now know I don't need ContinueWith. The question is, how do I do it with ContinueWith?
foreach + await will run Processes sequentially.
public async Task ProcessInputAsync(T input)
{
foreach (var processor in m_processors)
{
await processor.Process(input));
}
}
Btw. Process, should be called ProcessAsync
The method Task.ContinueWith does not understand async delegates, like Task.Run do, so when you return a Task it considers this as a normal return value and wraps it in another Task. So you end up receiving a Task<Task> instead of what you expected to get. The problem would be obvious if the AsyncProcessor.Process was returning a generic Task<T>. In this case you would get a compile error because of the illegal casting from Task<Task<T>> to Task<T>. In your case you cast from Task<Task> to Task, which is legal, since Task<TResult> derives from Task.
Solving the problem is easy. You just need to unwrap the Task<Task> to a simple Task, and there is a built-in method Unwrap that does exactly that.
There is another problem that you need to solve though. Currently your code suppresses all exceptions that may occur on each individual AsyncProcessor.Process, which I don't think it was intended. So you must decide which strategy to follow in this case. Are you going to propagate the first exception immediately, or you prefer to cache them all and propagate them at the end bundled in an AggregateException, like the Task.WhenAll does? The example bellow implements the first strategy.
public class CompositeAsyncProcessor<T>
{
//...
public Task Process(T input)
{
Task current = Task.CompletedTask;
foreach (AsyncProcessor<T> processor in m_processors)
{
current = current.ContinueWith(antecessor =>
{
if (antecessor.IsFaulted)
return Task.FromException<T>(antecessor.Exception.InnerException);
return processor.Process(input);
},
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default
).Unwrap();
}
return current;
}
}
I have used an overload of ContinueWith that allows configuring all the options, because the defaults are not ideal. The default TaskContinuationOptions is None. Configuring it to ExecuteSynchronously you minimize the thread switches, since each continuation will run in the same thread that completed the previous one.
The default task scheduler is TaskScheduler.Current. By specifying TaskScheduler.Default you make it explicit that you want the continuations to run in thread-pool threads (for some exceptional cases that won't be able to run synchronously). The TaskScheduler.Current is context specific, and if it ever surprises you it won't be in a good way.
As you see there are a lot of gotchas with the old-school ContinueWith approach. Using the modern await in a loop is a lot easier to implement, and a lot more difficult to get it wrong.

When to use "async" instead of returning a new Task.Run task?

So here I have a function
static bool Login(SignupData sd)
{
bool success=false;
/*
Perform login-related actions here
*/
}
And there is another function
static Task<bool> LoginAsync(SignupData sd)
{
return Task.Run<bool>(()=>Login(sd));
}
Now, I've come across a rather different implementation of this pattern, where you would add the async keyword to a function which returns Task<TResult> (so that it ends up looking like: async Task<TResult> LoginAsync(SignupData sd)). In this case, even if you return TResult instead of a Task<TResult>, the program still compiles.
My question here is, which implementation should be prefered?
static Task<bool> LoginAsync(SignupData sd)
{
return Task.Run<bool>(()=>Login(sd));
}
OR this one?
async static Task<bool> LoginAsync(SignupData sd)
{
bool success=Login(sd);
return success;
}
You shouldn't be doing either. Asynchronous methods are useful if they can prevent threads from being blocked. In your case, your method doesn't avoid that, it always blocks a thread.
How to handle long blocking calls depends on the application. For UI applications, you want to use Task.Run to make sure you don't block the UI thread. For e.g. web applications, you don't want to use Task.Run, you want to just use the thread you've got already to prevent two threads from being used where one suffices.
Your asynchronous method cannot reliably know what works best for the caller, so shouldn't indicate through its API that it knows best. You should just have your synchronous method and let the caller decide.
That said, I would recommend looking for a way to create a LoginAsync implementation that's really asynchronous. If it loads data from a database, for instance, open the connection using OpenAsync, retrieve data using ExecuteReaderAsync. If it connects to a web service, connect using the asynchronous methods for whatever protocol you're using. If it logs in some other way, do whatever you need to make that asynchronous.
If you're taking that approach, the async and await keywords make perfect sense and can make such an implementation very easy to create.
While HVD is correct, I will dive into async in an attempt to describe its intended use.
The async keyword, and the accompanying await keyword is a shortcut method of implementing non blocking code patterns within your application. While it plays along perfectly with the rest of the Task Parallel Library (TPL), it isn't usually used quite the same. It's beauty is in the elegance of how the compiler weaves in the asynchronicity, and allows it to be handled without explicitly spinning off separate threads, which may or may not be what you want.
For Example, let's look at some code:
async static Task<bool> DoStuffAsync()
{
var otherAsyncResult = doOtherStuffAsync();
return await otherAsyncResult
}
See the await keyword? It says, return to the caller, continue on until we have the result you need. Don't block, don't use a new thread, but basically return with a promise of a result when ready (A Task). The calling code can then carry on and not worry about the result until later when we have it.
Usually this ends up requiring that your code becomes non-blocking the whole way down (async all the way as it were), and often this is a difficult transition to understand. However, if you can it is incredibly powerful.
The better way to handle your code would be to make the synchronous code call the async one, and wait on it. That way you would be async as much as possible. It is always best to force that level as high as possible in your application, all the way to the UI if possible.
Hope that made sense. The TPL is a huge topic, and Async/Await really adds some interesting ways of structuring your code.
https://msdn.microsoft.com/en-us/library/hh191443.aspx

C# - does Task.FromResult incur a heavy penalty?

I'm a bit new to async coding with C#, and have encountered a few places where methods I have to implement (either from an interface or part of an inherited service, or just suggested default convention) are marked async and expect a Task<T> return.
But I don't always have async code to run; I don't always have something that needs an await operator.
So my ad-hoc workaround is to just return await Task.FromResult({normal code}); to these kinds of methods, like this...
public async Task<JsonResult> Id() {
// if the user is not authenticated, simply return false
if (!User.Identity.IsAuthenticated || String.IsNullOrEmpty(User.Identity.Name))
return await Task.FromResult(Json(false));
return await Task.FromResult((Json(User?.FindFirst("users/id")?.Value ?? null)));
}
This does solve the compile time errors, but I was wondering if there is an inherit problem with doing this. If so, what are good methods for getting around things marked as async that I cannot change?
Rather than creating a Task, then adding a continuation to that task that does literally noting but wrap it in an identical Task, just return the first task that you created.
Since you have nothing to await, there is no reason for the method to be marked as async.
Considering the performance costs of FromResult is a pointless discussion. You need to create a task based on the result that you have, so that work needs to be done. Considering how expensive it is is irrelevant as you have no alternative options. You could try to create your own FromResult method if you think you can write one that'll perform better than Microsoft's version.
That said, no, it is not particularly expensive of an operation.

Using the result of an async method

I have a simple async method with the signature:
public async Task<bool> AllowAccessAsync(string authenticatedUserToken)
When calling this method, I appear to have two options when assigning its result to a local variable:
bool response = null;
// option 1
await this.transportService.AllowAccessAsync(authenticatedUserToken).ContinueWith(task => response = task.Result);
// option 2
response = await this.transportService.AllowAccessAsync(authenticatedUserToken);
The first uses a continuation delegate to assign to the local variable, the second assigns the result directly to the variable.
Do these have the same result? Are there any advantages to either approach? Is there a better way to do this?
Do these have the same result?
Edit:
#Servy points out correctly that since the ContinueWith is simply a projection of the result. This means that both operations are semantically equivalent, but exception wise they'll behave differently.
Are there any advantages to either approach? Is there a better way to do this?
Edit 2:
The below remark relate to the use of async-await vs ContinueWith, generally. Looking specifically at both examples as they both use async-await, definitely use the latter, as both contain state-machine generation, but the latter will propagate an AggregateException in case an exception occurs.
async-await has the minimal overhead of producing a state-machine, while ContinueWith doesn't. On the other hand, using async-await lets you "feel" synchronous while actually being asynchronous, and saves you the verbosity of ContinueWith. I would definitely go with async-await, though I advise you to research the right path of using it, as there can be unexpected pitifuls.
By using async/await with Task Parallel Library's ContinueWith you're mixing patterns unnecessarily. There's a whole host of reasons not to do this unless you have no choice, not least of which is that async/await's SynchronizationContext is not preserved by the default implementation of ContinueWith.
So in short, option 2 is correct.
Do these have the same result?
Yes, both options will eventually set the same result into response. The only difference happens when there's an exception. In the first option The exception thrown will be an AggregateException wrapper over the actual exception while in the second one it will be the actual exception.
Are there any advantages to either approach?
There is absolutely no advantage to use ContinueWith in such a way. The second option has the advantages of having better exception handling and being much simpler to write and read.
Is there a better way to do this?
Not really, this is how you use async-await.
As Servy commented, this wasn't how ContinueWith was meant to be used. The ContinueWith equivalent is to put the rest of the method into the continuation. So instead of this:
public async Task FooAsync()
{
var response = await this.transportService.AllowAccessAsync(authenticatedUserToken);
Console.WriteLine(response);
}
You would do this:
public Task FooAsync()
{
return this.transportService.AllowAccessAsync(authenticatedUserToken).
ContinueWith(task => Console.WriteLine(task.GetAwaiter().GetResult()));
}
This does have some performance advantages as it doesn't need the async-await state machine but it's very complicated to get right.
It has more to do with coding style.
The first style might be useful when you have a large workflow which might want to assign different continuations when executing the promise. However it relies on closures. I would not recommend this usage since it's not always predictable. The ContinueWith should be used when you create workflows and each step relies only on the previous ones, and does not communicate with the outside scope, except by delivering a task that yields the final result (which you would then await).
The second one is useful when you are just interested in the result.
Also ContinueWith allows you to specify a TaskScheduler since the one that comes default with your application might not be the one you want.
More information on TaskScheduler here:
http://blog.stephencleary.com/2015/01/a-tour-of-task-part-7-continuations.html

Need an execution context for combination of async and TPL code

I'm looking for an execution context which plays nicely with async/await and with the TPL at the same time in the following way (expected behavior):
async Task<string> ReadContext(string slot)
{
// Perform some async code
...
return Context.Read(slot);
}
(1) Playing nicely with async/await
Context.Store("slot", "value");
await DoSomeAsync();
Assert.AreEqual("value", Context.Read("slot"));
Context.Store("slot", "value");
var value = await ReadContext("slot");
Assert.AreEqual("value", value);
(2) Playing nicely with Task.Run()
Context.Store("slot", "value");
var task = Task.Run(() => ReadContext("slot"));
Assert.IsNull(task.Result);
(3) Playing nicely with an awaited Task
Context.Store("slot", "value");
var value = await Task.Run(() => ReadContext("slot"));
Assert.AreEqual("value", value);
(3) is not essential but would be nice. I use CallContext now but it fails at (2) as the values stored in it are accessible even in manually ran tasks, even in those ran using Task.Factory.StartNew(..., LongRunning) which should enforce running the task on a separate thread.
Is there any way to accomplish that?
Your real question is in your comment:
I need a place to store NHibernate sessions in ASP.NET application. HttpContext works fine (and respects async/await) if I'm inside a request context, but it is unavailable once I jump into manually ran tasks.
First off, you should be avoiding "manually run tasks" in an ASP.NET application at all; I have a blog post on the subject.
Secondly, storing things in HttpContext.Items is sort of a hack. It can be useful in a handful of situations, but IMO managing NHibernate sessions is something that should be designed properly into your application. That means you should be passing around the session (or a service providing access to the session) either in your method calls or injected into each type that needs it.
So, I really think that a "context" like you're looking for is a wrong solution. Even if it were possible, which it is not.
As #Noseratio noted, requirements (2) and (3) cannot both be met. Either the code executing in the Task.Run has access or it does not; it can't be both.
As you've discovered, requirements (1) and (3) can be met by the logical call context (note to Googlers: this only works under .NET 4.5 and only if you store immutable data; details on my blog).
There is no easy way to satisfy (1) and (2) unless you manually remove the data (FreeNamedDataSlot) at the beginning of the code in Task.Run. I think there may be another solution but it would require custom awaitables at every await, which is completely cumbersome, brittle, and unmaintainable.

Categories

Resources