经常在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