To recap some terminology, Generators like Coroutines are generalizations of Subroutines. Both Coroutines and Generators allow multple entry points to allow execution to be temporarly suspended and then later resumed. Whereas a Subroutine have only one point of entry and they return only once.
What distinguishes Coroutines from Generators is what is returned in the yield. Coroutines yield the next Coroutine to be invoked (or resumed). Generators yield a value to be returned to the parent function.
When yield is used it must be within an iterator block or a function which return IEnumerable. As such the resulting function is a Generator and not a Coroutine.
The good news is that Coroutines can be created or emulated from Generators by using a Dispatching function.
Consider the following code in C#:
class Program
{
static ListstringBuffer;
enum NextMethod
{
Produce,
Consume
}
static void Main(string[] args)
{
stringBuffer = new List();
Dispatcher();
}
private static void Dispatcher()
{
IEnumeratorenumeratorProduce = produceCollection().GetEnumerator();
IEnumeratorenumeratorConsume = consumeCollection().GetEnumerator();
IEnumeratorenumerator = enumeratorProduce;
while (enumerator.MoveNext())
{
NextMethod next = enumerator.Current;
if (next == NextMethod.Produce)
{
enumerator = enumeratorProduce;
}
if (next == NextMethod.Consume)
{
enumerator = enumeratorConsume;
}
}
}
private static IEnumerableproduceCollection()
{
int i = 0;
while (true)
{
stringBuffer.Add(i.ToString());
i++;
yield return NextMethod.Consume;
}
}
private static IEnumerableconsumeCollection()
{
int i = 0;
while (true)
{
Console.WriteLine(stringBuffer[0]);
stringBuffer.RemoveAt(0);
yield return NextMethod.Produce;
}
}
}
Ideally we would like produceCollection and consumeCollection to yield control to each other.
Here the same effect is accomplished by yielding an enum that is then interpreted by the Dispatcher function to invoke the correct Generator. If you set breakpoints on all the lines of the code you will see that execution within the Generator routines produceCollection and consumeCollection picks up on the line where it last left off.
permalink
No comments:
Post a Comment