利用迭代器在.NET中实现“超轻量级线程”


 经常在python,lua之类的脚本语言看到 超轻量级线程的概念,动辄上百万的线程,硕大的线程数量非常的养眼,今天突发奇想,在c#下也来弄个超轻量线程的实现,虽然很简陋,但是希望能和大家一起来讨论讨论。

  且不说超轻量级的线程有用无用。其实现原理基本上都是在单线程中来模拟线程的切换,由于没有线程切换的开销,所以看着比系统线程要快。在python中一般通过yield关键字来实现。翻遍msdn发现c#也有yield return的关键字。yield return 用于实现迭代器。什么是迭代器呢,这是.NET2.0所带来的特征,如果不清楚请参见

  http://msdn.microsoft.com/zh-cn/library/dscyy5s0(VS.80).aspx

  其大意是:

  yield 关键字用于指定返回的值。到达 yield return 语句时,会保存当前位置。下次调用迭代器时将从此位置重新开始执行。

  这段对我们将要实现的功能尤其重要,其实一言盖之,yield可以把一个方法分成几段来执行。但是在C#里有限制,在调用yield的方法的返回值必须是 IEnumerable,其实说白了,其实是编译器自动把这段方法转换成了一个迭代器的对象,这样一段调用其实也就是在编译的时候就已经被分段了。根据 msdn的原文描述就是:

  迭代器是 C# 2.0 中的新功能。迭代器是方法、get 访问器或运算符,它使您能够在类或结构中支持 foreach 迭代,而不必实现整个 IEnumerable 接口。您只需提供一个迭代器,即可遍历类中的数据结构。当编译器检测到迭代器时,它将自动生成 IEnumerable 或 IEnumerable<T> 接口的 Current、MoveNext 和 Dispose 方法。

  要通过yield来模拟线程,我们必须有线程体,由于yield的限制,我们就通过迭代器的方法来作为线程体,然后每个线程一个对象,每个对象里包含一个迭代器对象,然后在一个大循环里来调用。代码如下:
1using System;
  2using System.Collections;
  3using System.Collections.Generic;
  4
  5public class MyClass
  6{
  7    public static void RunSnippet()
  8    {
  9        ThreadLite tl=new ThreadLite();
 10        tl.AddActor(T1);
 11        tl.AddActor(T1);
 12        tl.Run();
 13        
 14    }
 15    public static IEnumerable T1(int id){
 16        for(int i=0;i<10;i++){
 17            Console.WriteLine("Thread "+id+" print "+i);
 18            yield return id;
 19        }
 20    }
 21    public static IEnumerable T2(int id){
 22        for(int i=0;i<8;i++){
 23            Console.WriteLine("Thread "+id+" print "+i);
 24            yield return id;
 25        }
 26    }
 27    
 28    
 29    Helper methods#region Helper methods
 30    
 31    public static void Main()
 32    {
 33        try
 34        {
 35            RunSnippet();
 36        }
 37        catch (Exception e)
 38        {
 39            string error = string.Format("---\nThe following error occurred while executing the snippet:\n{0}\n---", e.ToString());
 40            Console.WriteLine(error);
 41        }
 42        finally
 43        {
 44            Console.Write("Press any key to continue");
 45            Console.ReadKey();
 46        }
 47    }
 48
 49    private static void WL(object text, params object[] args)
 50    {
 51        Console.WriteLine(text.ToString(), args);    
 52    }
 53    
 54    private static void RL()
 55    {
 56        Console.ReadLine();    
 57    }
 58    
 59    private static void Break() 
 60    {
 61        System.Diagnostics.Debugger.Break();
 62    }
 63
 64    #endregion
 65}
 66
 67class ThreadLite{
 68    int currentid = 1;
 69    public delegate IEnumerable ActorHandler(int id);
 70    private List<IEnumerator> ActionList;
 71    public ThreadLite(){
 72        ActionList=new List<IEnumerator>();
 73    }
 74    public void AddActor(ActorHandler actor){
 75        Actor act=new Actor(actor);
 76        act.ID=this.currentid;
 77        ActionList.Add(act.GetEnumerator());
 78        this.currentid++;
 79    }
 80    
 81    public void Run(){
 82        int fc = 0;
 83        while(true){
 84            foreach(IEnumerator ie in ActionList){
 85                if(!ie.MoveNext()){
 86                    fc++;
 87                }
 88            }
 89            if(fc==ActionList.Count){
 90                break;
 91            }
 92        }
 93        
 94    }
 95    
 96    class Actor{
 97        public int ID{
 98            get;
 99            set;
100        }
101
102        ThreadLite.ActorHandler hdl;
103        public Actor(ThreadLite.ActorHandler handler){
104            hdl=handler;
105        }
106        public IEnumerator GetEnumerator(){
107            IEnumerable ieb = hdl(ID);
108            return ieb.GetEnumerator();
109        }
110    }
111    
112}

执行结果如下:

a



相关阅读:
JS 建立对象的方法
discuz 分类信息设置教程(图文教程、DZX系列)
用CSS开发时髦的导航栏图例教程
php网页后退不再出现过期
只需五个小技巧便能让xp系统更快运行
window.onload和body onload
非常不错的模拟打字效果,目前仅支持纯文本、BR标签、和P标签
PHP基础教程(6):PHP运算符
JavaScript的类型简单说明
CSS:相同元素不同结构重复定义的问题
Linux下建立GPRS无线Modem拨号方法
js:校验IPv6地址的正则表达式
在Jsp Servlet中页面重新定向总汇
系统设置--lilo
快速导航

Copyright © 2016 phpStudy |