How would you implement something that works similarly to the Async CTP await keyword? Is there a simple implementation that works like await in all cases, or does await require different implementations for different scenarios?
The new await keyword has similar semantics to the existing yield return keyword in that they both cause the compiler to generate the continuation style state machine for you. So it is possible to hack something together using iterators that has some of the same behaviors as the Async CTP.
Here is what it would look like.
public class Form1 : Form
{
private void Button1_Click(object sender, EventArgs e)
{
AsyncHelper.Invoke<bool>(PerformOperation);
}
private IEnumerable<Task> PerformOperation(TaskCompletionSource<bool> tcs)
{
Button1.Enabled = false;
for (int i = 0; i < 10; i++)
{
textBox1.Text = "Before await " + Thread.CurrentThread.ManagedThreadId.ToString();
yield return SomeOperationAsync(); // Await
textBox1.Text = "After await " + Thread.CurrentThread.ManagedThreadId.ToString();
}
Button2.Enabled = true;
tcs.SetResult(true); // Return true
}
private Task SomeOperationAsync()
{
// Simulate an asynchronous operation.
return Task.Factory.StartNew(() => Thread.Sleep(1000));
}
}
Since yield return generates an IEnumerable our coroutine must return an IEnumerable. All of the magic happens inside the AsyncHelper.Invoke method. This is what gets our coroutine (masquerading as a hacked iterator) going. It takes special care to make sure the iterator is always executed on the current synchronization context if one exists which is important when trying to simulate how await works on a UI thread. It does this by executing the first MoveNext synchronously and then using SynchronizationContext.Send to do the rest from a worker thread which is also used to asynchronously wait on the individual steps.
public static class AsyncHelper
{
public static Task<T> Invoke<T>(Func<TaskCompletionSource<T>, IEnumerable<Task>> method)
{
var context = SynchronizationContext.Current;
var tcs = new TaskCompletionSource<T>();
var steps = method(tcs);
var enumerator = steps.GetEnumerator();
bool more = enumerator.MoveNext();
Task.Factory.StartNew(
() =>
{
while (more)
{
enumerator.Current.Wait();
if (context != null)
{
context.Send(
state =>
{
more = enumerator.MoveNext();
}
, null);
}
else
{
enumerator.MoveNext();
}
}
}).ContinueWith(
(task) =>
{
if (!tcs.Task.IsCompleted)
{
tcs.SetResult(default(T));
}
});
return tcs.Task;
}
}
The whole bit about the TaskCompletionSource was my attempt at replicating the way await can "return" a value. The problem is that the coroutine has to actually return an IEnumerable since it is nothing more than a hacked iterator. So I needed to come up with an alternate mechanism to capture a return value.
There are some glaring limitations with this, but I hope this gives you the general idea. It also demonstrates how the CLR could have one generalized mechanism for implementing coroutines for which await and yield return would use ubiquitously, but in different ways to provide their respective semantics.
await always involves the same kind of transformation - but it's a pretty painful one. The library side of await isn't too complicated, but the tricky bit is that the compiler builds a state machine for you, allowing the continuation to jump back to the right place.
It's possible that my some hacky use of iterator blocks (yield return) you could fake something similar... but it would be pretty ugly.
I gave a DevExpress webinar on what the compiler is doing behind the scenes a few weeks ago - that shows decompiled code from a couple of examples, as well as explaining how the compiler builds a task to return, and what the "awaiter" has to do. It may be useful to you.
There are few implementations and examples of coroutines made out of iterators (yield).
One of the examples is Caliburn.Micro framework, that uses this patter for asynchronous GUI operations. But it can easily be generalised for general async code.
The MindTouch DReAM framework implements Coroutines on top of the Iterator pattern which is functionally very similar to Async/Await:
async Task Foo() {
await SomeAsyncCall();
}
vs.
IYield Result Foo() {
yield return SomeAsyncCall();
}
Result is DReAM's version of Task. The framework dlls work with .NET 2.0+, but to build it you need 3.5, since we're using a lot of 3.5 syntax these days.
Bill Wagner from Microsoft wrote an article in MSDN Magazine about how you can use the Task Parallel Library in Visual Studio 2010 to implement async like behavior without adding a dependency on the async ctp.
It uses Task and Task<T> extensively which also has the added benefit that once C# 5 is out, your code will be well prepared to start using async and await.
From my reading, the major differences between yield return and await is that await can provide explicitly return a new value into the continuation.
SomeValue someValue = await GetMeSomeValue();
whereas with yield return, you'd have to accomplish the same thing by reference.
var asyncOperationHandle = GetMeSomeValueRequest();
yield return asyncOperationHandle;
var someValue = (SomeValue)asyncOperationHandle.Result;
Related
I'm trying to design a public method that returns a quick result and, if needed, kicks off a long-running background task.
The result is retrieved within the method pretty quickly, and once it is retrieved it needs to be immediately available to the caller, without waiting for the potential background task to complete.
The background task is either not needed at all, or it must run for a significant amount of time - longer than the caller and all other logic in the program would take to complete without it.
Looking through the MS docs, the best design option I can come up with is to return two things from this method: the result, as well as a Task for the background task.
I don't see a better way to do this, but there are some downsides: first, the responsibility for making sure the background task completes falls on the caller of the method, even though the caller really just wants to consume the immediate result and not be concerned with the behind-the-scene stuff. Second, it is awkward to return null if the background task isn't needed to begin with: now the caller must ensure the task isn't null, in addition to making sure it completes if it is null.
What other options are available for this sort of situation?
Here's an example of what my current design looks like:
public async Task<Tuple<string, Task>> GetAndSave() {
var networkResult = await GetFromNetworkAsync();
if (NeedsToSave(networkResult)) {
var saveTask = SaveToDiskAsync(networkResult);
return new Tuple<string, Task>(networkResult, saveTask);
}
else {
return new Tuple<string, Task>(networkResult, null);
}
}
first, the responsibility for making sure the background task completes falls on the caller of the method, even though the caller really just wants to consume the immediate result and not be concerned with the behind-the-scene stuff.
If it's important to make sure the background task completes then instead of returning the Task you could hand it off to another object (that has been injected into the class that has your GetAndSave method). For example:
public class Foo
{
readonly Action<Task> _ensureCompletion;
public Foo(Action<Task> ensureCompletion)
{
_ensureCompletion = ensureCompletion;
}
public async Task<string> GetAndSaveAsync() // Your method
{
string networkResult = await GetFromNetworkAsync();
if (NeedsToSave(networkResult))
{
Task saveTask = SaveToDiskAsync(networkResult);
_ensureCompletion(saveTask); // This is a synchronous call... no await keyword here. And it returns `void`
}
return networkResult;
}
Task<string> GetFromNetworkAsync() {...}
bool NeedsToSave(string x) {...}
Task SaveToDiskAsync(string x) {...}
}
Now you can inject whatever follow-up behavior you desire for the saveTask. For example, you could write stuff out to the console depending on how it goes:
async Task DoStuff()
{
var foo = new Foo(async task =>
// ^^^^^ More on this in a moment
{
try
{
await task;
Console.Writeline("It worked!");
}
catch (Exception e)
{
Console.Writeline(e.ToString());
}
});
var immediateResult = await foo.GetAndSaveAsync();
// do stuff with `immediateResult`
}
Now, the thing that might be confusing about this (and the power behind this type of solution) is how you can have a synchronous call on the one hand:
_ensureCompletion(saveTask); // This is a synchronous call... no await keyword here
...that does asynchronous things:
var foo = new Foo(async task => ...);
// ^^^^^ This statement lambda is asynchronous
(The injected delegate might even write out to the console on a different thread than whatever thread called GetAndSaveAsync()!)
There's no magic here. It all comes down to SynchronizationContext and the inner workings of async/await.
When the compiler encounters the await keyword (in an async context) then it will do a few things:
Turn everything after the await into a continuation (basically a delegate with some state)
Replace the await keyword with something like SynchronizationContext.Current.Post(continuation)
In other words, this:
async void EnsureCompletion(Task task)
{
try
{
await task;
Console.Writeline("It worked!");
}
catch (Exception e)
{
Console.Writeline(e.ToString());
}
}
...gets turned into something like this:
void EnsureCompletion(Task task)
{
try
{
task.ContinueWith(t => SynchronizationContext.Current.Post(_ =>
{
if (t.IsCompletedSuccessfully)
{
Console.Writeline("It worked!");
}
else
{
Console.Writeline(task.Exception.ToString());
}
});
}
catch (Exception e)
{
Console.Writeline(e.ToString());
}
}
As you can see, EnsureCompletion is an entirely synchronous function that does (almost) the exact same thing as its asynchronous form. Notice how it returns void and everything. This is how you can jam an asynchronous statement lambda into a delegate parameter that has a synchronous signature.
I hinted that the console writing might happen on a totally different thread. That's because async/await is orthogonal to threading. It depends on whatever the currently assigned implementation of SynchronizationContext is programmed to do. Unless you're using WPF or WinForms then by default there will be no SynchronizationContext and continuations (the things that get passed to SynchronizationContext.Post) will just be tossed over to whatever thread happens to be free in the default thread pool.
Second, it is awkward to return null if the background task isn't needed to begin with: now the caller must ensure the task isn't null, in addition to making sure it completes if it is null.
I'm of the opinion that null was a design mistake in C#. (Ask me what some other ones are :) ). If you return null from this method:
public Task DoSomethingAsync()
{
return null; // Compiles just fine
}
...then anyone who uses it will encounter a NullReferenceException when they await it.
async Task Blah()
{
await DoSomethingAsync(); // Wham! NullReferenceException :(
}
(the reason why comes back to how the compiler desugurs the await keyword)
...and it's awkward to have to check for nulls everywhere.
Much better would be to just return Task.CompletedTask as #juharr said.
But if you just hand off the background task like I showed above then you don't have to worry about this.
Which of these is the best option when working with caching in C#?
I am interested at the compiler level which of these is the most elegant / performant solution.
E.g does the .net compiler use any tricks to know that when code will run synchronously and avoid creating/running unnecessary async await code?
Option 1, Use async/await and use Task.FromResult for cached values;
public async Task<T> GetValue<T>(string key)
{
if (_cache.containsKey(key))
{
// 99% of the time will hit this
return Task.FromResult(_cache.GetItem(key));
}
return await _api.GetValue(key);
}
Option 2, Avoid async/await and use something like GetAwaiter().GetResult() for the few times the API Endpoint will be hit.
public T GetValue<T>(string key)
{
if (_cache.containsKey(key))
{
// 99% of the time will hit this
return _cache.GetItem(key);
}
return _api.GetValue(key).GetAwaiter().GetResult();
}
Any insights would be very much appreciated.
The official approach is to cache the Task<T>, and not the T.
This also has the advantage that if someone requests the value, you can kick off the request to fetch the value and then cache the resulting, in-progress Task<T>. If someone else requests the cached value before the request has completed, they're also given the same in-progress Task<T>, and you don't end up making two requests.
For example:
public Task<T> GetValue<T>(string key)
{
// Prefer a TryGet pattern if you can, to halve the number of lookups
if (_cache.containsKey(key))
{
return _cache.GetItem(key);
}
var task = _api.GetValue(key);
_cache.Add(key, task);
return task;
}
Note that you need to think about failure in this case: if the request to the API fails, then you'll be caching a Task which contains an exception. This might be what you want, but it might not be.
If for some reason you can't do this, then the official advice is to use ValueTask<T> for high-performance scenarios. This type has some gotchas (such as you can't await it twice), so I recommend reading this. If you don't have high performance requirements, Task.FromResult is fine.
Your first won't work. The simplest, and the one to go for most of the time is:
public async Task<T> GetValueAsync<T>(string key)
{
if (_cache.ContainsKey(key))
{
return _cache.GetItem(key);
}
T result = await _api.GetValueAysnc(key);
_cache.Add(key, result);
return result;
}
Or better still if possible:
public async Task<T> GetValueAsync<T>(string key)
{
if (_cache.TryGet(key, out T result))
{
return result;
}
result = await _api.GetValueAysnc(key);
_cache.Add(key, result);
return result;
}
This works fine and will return an already-completed task when the value was in the cache, so awaiting it will continue immediately.
However if the value is in the cache much of the time and the method is called often enough for the extra apparatus around async to make a difference then you can avoid it entirely in such a case:
public Task<T> GetValueAsync<T>(string key)
{
if (_cache.TryGet(key, out Task<T> result))
{
return result;
}
return GetAndCacheValueAsync(string key);
}
private async Task<T> GetAndCacheValueAsync<T>(string key)
{
var task = _api.GetValueAysnc(key);
result = await task;
_cache.Add(key, task);
return result;
}
Here if the value is cached we avoid both the state-machine around async and also the creation of a new Task<T> since we have stored an actual Task. Each of these are only done in the first case.
What you are looking for probably is memoization.
A implementation might be something like this:
public static Func<T, TResult> Memoize<T, TResult>(this Func<T, TResult> f)
{
var cache = new ConcurrentDictionary<T, TResult>();
return a => cache.GetOrAdd(a, f);
}
Measure(() => slowSquare(2)); // 00:00:00.1009680
Measure(() => slowSquare(2)); // 00:00:00.1006473
Measure(() => slowSquare(2)); // 00:00:00.1006373
var memoizedSlow = slowSquare.Memoize();
Measure(() => memoizedSlow(2)); // 00:00:00.1070149
Measure(() => memoizedSlow(2)); // 00:00:00.0005227
Measure(() => memoizedSlow(2)); // 00:00:00.0004159
Source
First of all, this calls for linking the speed rant:
https://ericlippert.com/2012/12/17/performance-rant/
Microoptimisations like these are usually left to the JiT. My rule of thumb is that if you really need that difference, then you are propably dealing with realtime programming. And for Realtime Proramming a Garbage Collected runtime like .NET was propably the wrong environment to begin with. Something with direct memory management like unsafe code - even native C++ or Assembler - would have been better.
Secondly, a task might just be the wrong tool here. Maybe what you actually want is something like Lazy[T]? Or any of the 5 different Chache classes? (as with timer, there is about one for specific User Interface technology).
It is possible to use any tool for many purposes. But tasks are for Multitasking and there are better tools for caching and lazy initialisation. And Lazy[T] is even inherently Thread save.
I am trying to you use yield and return a result from converting X into Y in an async task. But, I am getting an error on select.
The error is:
Error CS1942 The type of the expression in the select clause is
incorrect. Type inference failed in the call to 'Select'.
public async Task<Result<dynamic>> GetYAsync(IEnumerable<X> infos)
{
return Task.WhenAll(from info in infos.ToArray() select async ()=>
{
yield return await new Y(info.Id, "Start");
});
}
Short answer: you can't use an asynchronous yield statement.
But in most cases, you don't need to. Using LINQ you can aggregate all tasks before passing them into Task.WaitAll. I simplified your example to return an IEnumerable<int>, but this will work with every type.
public class Program
{
public static Task<int> X(int x)
{
return Task.FromResult(x);
}
public static async Task<IEnumerable<int>> GetYAsync(IEnumerable<int> infos)
{
var res = await Task.WhenAll(infos.Select(info => X(info)));
return res;
}
public static async void Main()
{
var test = await GetYAsync(new [] {1, 2, 3});
Console.WriteLine(test);
}
}
Your example has another error await new Y(...), a constructor cannot be asynchronous, therefore I replaced it with an asynchronous function. (As hinted in the comments, it is technically possible to create a custom awaitable type and create this type with new, although this is rarely used),
The example above uses infos.Select to create a list of pending tasks, returned by invoking the function X. This list of tasks will then be awaited and returned.
This workaround should fit most cases. Real asynchronous iterators, as for example in JavaScript, are not supported in .Net.
Update: This feature is currently suggested as a language proposal: Async Streams. So maybe we will see this in the future.
Update: If you need asynchronous iterators, there are a few options currently available:
Reactive Stream, RX.Net, which provides you with asynchronous observable streams based on events.
There are implementations of asynchronous iterators or asynchronous enumerables AsyncEnumerable or
.Net Async Enumerable
You do not. Async Enum support (and yield is there to implement enumerable) comes with C# 8 some point in 2019 as it looks. So, for now the answer is simply that you do not.
The reason you get the error is that you can also not returna Result. Yield (return) is specific to implementing enumerations. Your method signature does not match.
It's recommended that one use ConfigureAwait(false) whenever when you can, especially in libraries because it can help avoid deadlocks and improve performance.
I have written a library that makes heavy use of async (accesses web services for a DB). The users of the library were getting a deadlock and after much painful debugging and tinkering I tracked it down to the single use of await Task.Yield(). Everywhere else that I have an await, I use .ConfigureAwait(false), however that is not supported on Task.Yield().
What is the recommended solution for situations where one needs the equivalent of Task.Yield().ConfigureAwait(false)?
I've read about how there was a SwitchTo method that was removed. I can see why that could be dangerous, but why is there no equivalent of Task.Yield().ConfigureAwait(false)?
Edit:
To provide further context for my question, here is some code. I am implementing an open source library for accessing DynamoDB (a distributed database as a service from AWS) that supports async. A number of operations return IAsyncEnumerable<T> as provided by the IX-Async library. That library doesn't provide a good way of generating async enumerables from data sources that provide rows in "chunks" i.e. each async request returns many items. So I have my own generic type for this. The library supports a read ahead option allowing the user to specify how much data should be requested ahead of when it is actually needed by a call to MoveNext().
Basically, how this works is that I make requests for chunks by calling GetMore() and passing along state between these. I put those tasks in a chunks queue and dequeue them and turn them into actual results that I put in a separate queue. The NextChunk() method is the issue here. Depending on the value of ReadAhead I will keeping getting the next chunk as soon as the last one is done (All) or not until a value is needed but not available (None) or only get the next chunk beyond the values that are currently being used (Some). Because of that, getting the next chunk should run in parallel/not block getting the next value. The enumerator code for this is:
private class ChunkedAsyncEnumerator<TState, TResult> : IAsyncEnumerator<TResult>
{
private readonly ChunkedAsyncEnumerable<TState, TResult> enumerable;
private readonly ConcurrentQueue<Task<TState>> chunks = new ConcurrentQueue<Task<TState>>();
private readonly Queue<TResult> results = new Queue<TResult>();
private CancellationTokenSource cts = new CancellationTokenSource();
private TState lastState;
private TResult current;
private bool complete; // whether we have reached the end
public ChunkedAsyncEnumerator(ChunkedAsyncEnumerable<TState, TResult> enumerable, TState initialState)
{
this.enumerable = enumerable;
lastState = initialState;
if(enumerable.ReadAhead != ReadAhead.None)
chunks.Enqueue(NextChunk(initialState));
}
private async Task<TState> NextChunk(TState state, CancellationToken? cancellationToken = null)
{
await Task.Yield(); // ** causes deadlock
var nextState = await enumerable.GetMore(state, cancellationToken ?? cts.Token).ConfigureAwait(false);
if(enumerable.ReadAhead == ReadAhead.All && !enumerable.IsComplete(nextState))
chunks.Enqueue(NextChunk(nextState)); // This is a read ahead, so it shouldn't be tied to our token
return nextState;
}
public Task<bool> MoveNext(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if(results.Count > 0)
{
current = results.Dequeue();
return TaskConstants.True;
}
return complete ? TaskConstants.False : MoveNextAsync(cancellationToken);
}
private async Task<bool> MoveNextAsync(CancellationToken cancellationToken)
{
Task<TState> nextStateTask;
if(chunks.TryDequeue(out nextStateTask))
lastState = await nextStateTask.WithCancellation(cancellationToken).ConfigureAwait(false);
else
lastState = await NextChunk(lastState, cancellationToken).ConfigureAwait(false);
complete = enumerable.IsComplete(lastState);
foreach(var result in enumerable.GetResults(lastState))
results.Enqueue(result);
if(!complete && enumerable.ReadAhead == ReadAhead.Some)
chunks.Enqueue(NextChunk(lastState)); // This is a read ahead, so it shouldn't be tied to our token
return await MoveNext(cancellationToken).ConfigureAwait(false);
}
public TResult Current { get { return current; } }
// Dispose() implementation omitted
}
I make no claim this code is perfect. Sorry it is so long, wasn't sure how to simplify. The important part is the NextChunk method and the call to Task.Yield(). This functionality is used through a static construction method:
internal static class AsyncEnumerableEx
{
public static IAsyncEnumerable<TResult> GenerateChunked<TState, TResult>(
TState initialState,
Func<TState, CancellationToken, Task<TState>> getMore,
Func<TState, IEnumerable<TResult>> getResults,
Func<TState, bool> isComplete,
ReadAhead readAhead = ReadAhead.None)
{ ... }
}
The exact equivalent of Task.Yield().ConfigureAwait(false) (which doesn't exist since ConfigureAwait is a method on Task and Task.Yield returns a custom awaitable) is simply using Task.Factory.StartNew with CancellationToken.None, TaskCreationOptions.PreferFairness and TaskScheduler.Current. In most cases however, Task.Run (which uses the default TaskScheduler) is close enough.
You can verify that by looking at the source for YieldAwaiter and see that it uses ThreadPool.QueueUserWorkItem/ThreadPool.UnsafeQueueUserWorkItem when TaskScheduler.Current is the default one (i.e. thread pool) and Task.Factory.StartNew when it isn't.
You can however create your own awaitable (as I did) that mimics YieldAwaitable but disregards the SynchronizationContext:
async Task Run(int input)
{
await new NoContextYieldAwaitable();
// executed on a ThreadPool thread
}
public struct NoContextYieldAwaitable
{
public NoContextYieldAwaiter GetAwaiter() { return new NoContextYieldAwaiter(); }
public struct NoContextYieldAwaiter : INotifyCompletion
{
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation)
{
var scheduler = TaskScheduler.Current;
if (scheduler == TaskScheduler.Default)
{
ThreadPool.QueueUserWorkItem(RunAction, continuation);
}
else
{
Task.Factory.StartNew(continuation, CancellationToken.None, TaskCreationOptions.PreferFairness, scheduler);
}
}
public void GetResult() { }
private static void RunAction(object state) { ((Action)state)(); }
}
}
Note: I don't recommend actually using NoContextYieldAwaitable, it's just an answer to your question. You should be using Task.Run (or Task.Factory.StartNew with a specific TaskScheduler)
I noticed you edited your question after you accepted the existing answer, so perhaps you're interested in more rants on the subject. Here you go :)
It's recommended that one use ConfigureAwait(false) whenever when you
can, especially in libraries because it can help avoid deadlocks and
improve performance.
It's recommended so, only if you're absolutely sure that any API you're calling in your implementation (including Framework APIs) doesn't depend on any properties of synchronization context. That's especially important for a library code, and even more so if the library is suitable for both client-side and server-side use. E.g, CurrentCulture is a common overlook: it would never be an issue for a desktop app, but it well may be for an ASP.NET app.
Back to your code:
private async Task<TState> NextChunk(...)
{
await Task.Yield(); // ** causes deadlock
var nextState = await enumerable.GetMore(...);
// ...
return nextState;
}
Most likely, the deadlock is caused by the client of your library, because they use Task.Result (or Task.Wait, Task.WaitAll, Task.IAsyncResult.AsyncWaitHandle etc, let them search) somewhere in the outer frame of the call chain. Albeit Task.Yield() is redundant here, this is not your problem in the first place, but rather theirs: they shouldn't be blocking on the asynchronous APIs and should be using "Async All the Way", as also explained in the Stephen Cleary's article you linked.
Removing Task.Yield() may or may not solve this problem, because enumerable.GetMore() can also use some await SomeApiAsync() without ConfigureAwait(false), thus posting the continuation back to the caller's synchronization context. Moreover, "SomeApiAsync" can happen to be a well established Framework API which is still vulnerable to a deadlock, like SendMailAsync, we'll get back to it later.
Overall, you should only be using Task.Yield() if for some reason you want to return to the caller immediately ("yield" the execution control back to the caller), and then continue asynchronously, at the mercy of the SynchronizationContext installed on the calling thread (or ThreadPool, if SynchronizationContext.Current == null). The continuation well may be executed on the same thread upon the next iteration of the app's core message loop. Some more details can be found here:
Task.Yield - real usages?
So, the right thing would be to avoid blocking code all the way. However, say, you still want to make your code deadlock-proof, you don't care about synchronization context and you're sure the same is true about any system or 3rd party API you use in your implementation.
Then, instead of reinventing ThreadPoolEx.SwitchTo (which was removed for a good reason), you could just use Task.Run, as suggested in the comments:
private Task<TState> NextChunk(...)
{
// jump to a pool thread without SC to avoid deadlocks
return Task.Run(async() =>
{
var nextState = await enumerable.GetMore(...);
// ...
return nextState;
});
}
IMO, this is still a hack, with the same net effect, although a much more readable one than using a variation of ThreadPoolEx.SwitchTo(). Same as SwitchTo, it still has an associated cost: a redundant thread switch which may hurt ASP.NET performance.
There is another (IMO better) hack, which I proposed here to address the deadlock with aforementioned SendMailAsync. It doesn't incur an extra thread switch:
private Task<TState> NextChunk(...)
{
return TaskExt.WithNoContext(async() =>
{
var nextState = await enumerable.GetMore(...);
// ...
return nextState;
});
}
public static class TaskExt
{
public static Task<TResult> WithNoContext<TResult>(Func<Task<TResult>> func)
{
Task<TResult> task;
var sc = SynchronizationContext.Current;
try
{
SynchronizationContext.SetSynchronizationContext(null);
task = func(); // do not await here
}
finally
{
SynchronizationContext.SetSynchronizationContext(sc);
}
return task;
}
}
This hack works in the way it temporarily removes the synchronization context for the synchronous scope of the original NextChunk method, so it won't be captured for the 1st await continuation inside the async lambda, effectively solving the deadlock problem.
Stephen has provided a slightly different implementation while answering the same question. His IgnoreSynchronizationContext restores the original synchronization context on whatever happens to be the continuation's thread after await (which could be a completely different, random pool thread). I'd rather not restore it after await at all, as long as I don't care about it.
Inasmuch as the useful and legit API you're looking for is missing, I filed this request proposing its addition to .NET.
I also added it to vs-threading so that the next release of the Microsoft.VisualStudio.Threading NuGet package will include this API. Note that this library is not VS-specific, so you can use it in your app.
I want to write a class to simplify the asynchronous programing, like string s = mylib.BeginInvoek(test,"1"); here is my code:
public T BeginInvokeExWithReturnValue<T>(Func<T> actionFunction)
{
ExecWithReturnType<T> execWtihReturnValue = new ExecWithReturnType<T>(actionFunction);
IAsyncResult iar = execWtihReturnValue.BeginInvoke(new AsyncCallback(EndInvokeExWithReturnValue<T>), execWtihReturnValue);
// how to code here to return value
}
private void EndInvokeExWithReturnValue<T>(IAsyncResult iar)
{
ExecWithReturnType<T> execWtihReturnValue = (ExecWithReturnType<T>)iar.AsyncState;
execWtihReturnValue.EndInvoke(iar);
}
this BeginInvokeExWithReturnValue function has no input parameter, but returns a value,
But I don't know how to return a value from BeginInvokeExWithReturnValue function. Anyone who know this, Could you pls help me ? thx very much.
What you are trying to do right now is not async; if you want to return the T, just use:
return actionFunction();
It will be less overhead.
If you want async, and you are on 4.0, then the TPL may be a good option:
public Task<T> BeginInvokeExWithReturnValue<T>(Func<T> actionFunction)
{
var task = new Task<T>(actionFunction);
task.Start();
return task;
}
Now the caller can use:
var task = BeginInvokeExWithReturnValue(() => Whatever());
and then when desired, check for completion, block (Wait) for completion, register continuations, etc. Or just:
var result = task.Result; // implicit wait
Console.WriteLine(result);
This allows you to seamlessly write async code. Or in C# 5.0, seamlessly write continuations:
var result = await task; // continuation - this is **not** a wait
Console.WriteLine(result);
As David pointed out, the Invoke method is probably what you want, but if you're looking to write you're own variant, you just need to type cast the value to the generic (T, in your example) to satisfy your comment.
return (T) iar;
Following from the comments,
There are 3 models of Asyncronous development in .NET
APM - (BeginXXX EndXXX) Which you are using here, when the long running task completes it calls back into your code in the EndXXX method
EAP - Event based. In this model, when the long running task completes, an event is raised to inform your code.
TPL - New in .NET 4, this is the 'Task' based version. it looks most like Syncronous programming to client code, using a fluent interface. Its calls back to your code using continueWith.
Hope this helps