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?
相关问题
- Sorting 3 numbers without branching [closed]
- Graphics.DrawImage() - Throws out of memory except
- Generic Generics in Managed C++
- Why am I getting UnauthorizedAccessException on th
- 求获取指定qq 资料的方法
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:
vs.
Result
is DReAM's version ofTask
. 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.await
always involves the same kind of transformation - but it's a pretty painful one. The library side ofawait
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.
From my reading, the major differences between
yield return
andawait
is thatawait
can provide explicitly return a new value into the continuation.whereas with
yield return
, you'd have to accomplish the same thing by reference.The new
await
keyword has similar semantics to the existingyield 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.
Since
yield return
generates anIEnumerable
our coroutine must return anIEnumerable
. All of the magic happens inside theAsyncHelper.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 howawait
works on a UI thread. It does this by executing the firstMoveNext
synchronously and then usingSynchronizationContext.Send
to do the rest from a worker thread which is also used to asynchronously wait on the individual steps.The whole bit about the
TaskCompletionSource
was my attempt at replicating the wayawait
can "return" a value. The problem is that the coroutine has to actually return anIEnumerable
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
andyield return
would use ubiquitously, but in different ways to provide their respective semantics.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
andTask<T>
extensively which also has the added benefit that once C# 5 is out, your code will be well prepared to start usingasync
andawait
.