經常在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=n
ew 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