迭代器
CCR以新颖的方式使用了C# 2.0语言的迭代器功能:程序员可以用顺序的方式来编写代码,迭代返回(yielding)CCR仲裁器或者其他的CCR Task,而不需要使用delegates来嵌套异步行为(也叫做回调)。多步的异步逻辑也可以被写到一个迭代方法里,从而极大的提高代码的可读性,维护异步行为,并且由于迭代返回不会阻塞操作系统线程,所以可以伸缩到百万级别的未决操作。
例18.
{
// create an IterativeTask instance and schedule it
Arbiter.Activate(_taskQueue,
Arbiter.FromIteratorHandler(IteratorExample)
);
}
/// <summary>
/// Iterator method scheduled by the CCR
/// </summary>
IEnumerator<ITask> IteratorExample()
{
// accumulator variable
int totalSum = 0;
var portInt = new Port<int>();
// using CCR iterators we can write traditional loops
// and still yield to asynchronous I/O !
for (int i = 0; i < 10; i++)
{
// post current iteration value to a port
portInt.Post(i);
// yield until the receive is satisifed. No thread is blocked
yield return portInt.Receive();
// retrieve value using simple assignment
totalSum += portInt;
}
Console.WriteLine("Total:" + totalSum);
}
IEnumerator<ITask> IteratorExample()
{
这个方法的返回值表明了这是一个在CCR ITask实例上的C#迭代器
上面的yield return语句返回控制权给CCR调度器。它也返回一个由调用portInt.Receive扩展方法创建的ReceiverTask对象(ITask接口的实例)。CCR调度器
重要:永远不要再迭代器中返回永久接收器。在上面的yield语句中,Arbiter.Receive的persist参数是false(第一个参数)。如果接收器是永久的,yield永远不会被满足,所以迭代器会停止迭代,永远不会处理yield后的下一个语句。
通过本地变量隐式的传递参数
将CCR与CLR迭代器一起使用的好处来自于两个C#的语言特性:
- 匿名方法-我们已经在前面的例子中使用过这个特性,用来定义内联的delegate。
- 编译器“捕获”所有在匿名方法中引用的迭代方法里面的局部变量。这使得delegate可以使用这些定义在父方法中的局部变量。总是运行在其他线程中的delegate也可以将结果返回给父迭代器,而不需要任何的显式参数传递。
totalSum += portInt;
部分返回到协调原语
例19
{
Port<string> portString = new Port<string>();
Arbiter.Activate(
_taskQueue,
Arbiter.ReceiveWithIterator(false, portString, StringIteratorHandler)
);
}
IEnumerator<ITask> StringIteratorHandler(string item)
{
Console.WriteLine(item);
yield break;
}
上面的这个例子展示了如何指定一个迭代方法作为一个接收操作的结果(the outcome of a receive operation)。到现在为之,我们用于在仲裁器被满足时执行的方法都是传统的方法(methods)。Arbiter类包含一些方法,它们需要一个迭代器delegate(The Arbiter class contains methods that expect an iterator delegate for all the major coordination primitives (JoinReceiver, MultipleItemGather, Choice, Receiver, etc) giving the programmer the choice between regular methods or iterator methods for every CCR coordination primitive.)。仲裁器的实现依赖ITask而不是用户delegate,ITask隐藏了用户delegate的类型,所以仲裁器可以适应迭代或者非迭代方法。
例20.
{
// create a service instance
ServicePort servicePort = ServiceWithInterleave.Create(_taskQueue);
// send an update request
UpdateState updateRequest = new UpdateState();
updateRequest.State = "Iterator step 1";
servicePort.Post(updateRequest);
string result = null;
// wait for either outcome before continuing
yield return Arbiter.Choice(
updateRequest.ResponsePort,
response => result = response,
ex => Console.WriteLine(ex)
);
// if the failure branch of the choice executed, the result will be null
// and we will terminate the iteration
if (result == null)
yield break;
// print result from first request
Console.WriteLine("UpdateState response:" + result);
// now issue a get request
GetState get = new GetState();
servicePort.Post(get);
// wait for EITHER outcome
yield return Arbiter.Choice(
get.ResponsePort,
delegate(string response) { result = response; },
delegate(Exception ex) { Console.WriteLine(ex); }
);
// print result from second request
Console.WriteLine("GetState response:" + result);
}
迭代器嵌套
{
Console.WriteLine("Yielding to another iterator that will execute N asynchronous steps");
yield return new IterativeTask<int>(10, ChildIteratorMethod);
Console.WriteLine("Child iterator completed");
}
IEnumerator<ITask> ChildIteratorMethod(int count)
{
Port<int> portInt = new Port<int>();
for (int i = 0; i < count; i++)
{
portInt.Post(i);
// short form of receive that leaves item in port
yield return portInt.Receive();
// implicit operator extracts item from port
int result = portInt;
}
}
- 父迭代方法部分返回执行到一个新的IterativeTask实例。
- CCR把IterativeTask实例调度到当前迭代器使用的dispatcher queue实例上。Arbiter.FromIteratorHandler可以被用来替换显式创建一个IterativeTask。
- 子迭代方法在一个dispatcher线程中执行,并且部分返回10次到一个接收操作。一个循环被用来展示迭代器在异步操作外包裹循环是多么的容易和具有可读性。它也展示了父迭代器可以部分返回到任意复杂的子迭代器而不许知道子迭代中有多少异步环节。
posted on 2007-12-14 14:30 iceboundrock 阅读(961) 评论(0) 编辑 收藏 举报