您可以使用 IEnumerable 模拟协作微线程。不幸的是,这不适用于阻塞 API,因此您需要找到可以轮询的 API,或者具有可用于发送信号的回调的 API。
考虑一种方法
IEnumerable Thread ()
{
//do some stuff
Foo ();
//co-operatively yield
yield null;
//do some more stuff
Bar ();
//sleep 2 seconds
yield new TimeSpan (2000);
}
C# 编译器会将其解包到状态机中 - 但外观是协作微线程的外观。
该模式非常简单。您实现了一个“调度程序”,它保留了所有活动 IEnumerator 的列表。当它在列表中循环时,它使用 MoveNext () “运行”每个列表。如果 MoveNext 的值为 false,则线程已结束,调度程序将其从列表中删除。如果为真,则调度程序访问 Current 属性以确定线程的当前状态。如果它是 TimeSpan,则线程希望休眠,调度程序将其移动到某个队列中,当休眠时间跨度结束时,该队列可以刷新回主列表。
您可以使用其他返回对象来实现其他信号机制。例如,定义某种 WaitHandle。如果线程产生其中之一,则可以将其移至等待队列,直到发出句柄信号为止。或者,您可以通过生成等待句柄数组来支持 WaitAll。你甚至可以实现优先级。
我在大约 150LOC 中完成了这个调度程序的简单实现,但我还没有开始写博客代码。这是为了我们的 PhyreSharp PhyreEngine 包装器(不会公开),在我们的一个演示中,它似乎可以很好地控制几百个字符。我们从 Unity3D 引擎中借用了这个概念——他们有一些在线文档从用户的角度来解释它。