从无到有实现.net协程(三)

在前一篇中,还存在一个问题,当没有请求进来时,线程仍然会轮询执行,这样造成了CPU资源的浪费,因此,需要进一步改进,实现仅当有请求进入时,才启动线程。

还是先实现协程容器

  1 /// <summary>
  2     /// 基于自动多线程的协程容器实现
  3     /// </summary>
  4     public class CoroutineContainerMultipleAuto : ICoroutineContainer
  5     {
  6 
  7         /// <summary>
  8         /// 存储多线程协程单元项
  9         /// </summary>
 10         private List<MultipleItem> _multipleItems = new List<MultipleItem>();
 11 
 12         /// <summary>
 13         /// 设定的线程数
 14         /// </summary>
 15         private int _threadCount;
 16         /// <summary>
 17         /// 错误处理
 18         /// </summary>
 19         private Action<ICoroutineUnit,Exception> _errorHandle;
 20         public CoroutineContainerMultipleAuto(int threadCount,Action<ICoroutineUnit,Exception> errorHandle)
 21         {
 22             _threadCount = threadCount;
 23             _errorHandle = errorHandle;
 24         }
 25         public void Register(ICoroutineUnit unit)
 26         {
 27             //随机分摊请求
 28             Random random = new Random();
 29             var index = random.Next(0, _threadCount);
 30 
 31             lock (_multipleItems[index].AddUnits)
 32             {
 33                 _multipleItems[index].AddUnits.Add(new UnitItem() { Unit = unit, UnitResult = null });
 34                 //要求协程处理线程启动
 35                 _multipleItems[index].Run();
 36             }
 37 
 38         }
 39         /// <summary>
 40         /// 容器启动
 41         /// 这里并不会真正启动线程
 42         /// </summary>
 43         public void Run()
 44         {
 45             for (var index = 0; index <= _threadCount - 1; index++)
 46             {
 47                 var multipleItem = new MultipleItem() { Units = new List<UnitItem>(), AddUnits = new List<UnitItem>(), ErrorHandle=_errorHandle };
 48                 _multipleItems.Add(multipleItem);
 49 
 50             }
 51 
 52 
 53 
 54         }
 55 
 56 
 57         private class UnitItem
 58         {
 59             public ICoroutineUnit Unit { get; set; }
 60             public IEnumerator<Task> UnitResult { get; set; }
 61         }
 62 
 63         /// <summary>
 64         /// 多线程协程单元项
 65         /// </summary>
 66         private class MultipleItem
 67         {
 68             public List<UnitItem> Units
 69             {
 70                 get; set;
 71             }
 72 
 73             public List<UnitItem> AddUnits
 74             {
 75                 get; set;
 76             }
 77 
 78             public Action<ICoroutineUnit,Exception> ErrorHandle { get; set; }
 79 
 80 
 81             private bool _running = false;
 82             private bool _continue = true;
 83 
 84             /// <summary>
 85             /// 仅当外部调用方调用时才启动
 86             /// 同时保证只有一个线程启动
 87             /// </summary>
 88             public void Run()
 89             {
 90                 lock (this)
 91                 {
 92                     if (_running)
 93                     {
 94                         _continue = true;
 95                     }
 96                     else
 97                     {
 98                         _continue = false;
 99                     }
100 
101                 }
102 
103                 if (!_running)
104                 {
105                     lock (this)
106                     {
107                         _running = true;
108                     }
109 
110                     Task.Run(() =>
111                         {
112 
113 
114                                 while (true)
115                                 {
116                                     lock (this)
117                                     {
118                                         _continue = false;
119                                     }
120 
121                                     while (true)
122                                     {
123                                         lock (AddUnits)
124                                         {
125                                             foreach (var addItem in AddUnits)
126                                             {
127                                                 Units.Add(addItem);
128                                             }
129                                             AddUnits.Clear();
130                                         }
131 
132 
133                                         if (Units.Count == 0)
134                                         {
135                                             break;
136                                         }
137 
138                                         foreach (var item in Units)
139                                         {
140                                             if (item.UnitResult == null)
141                                             {
142                                                 var result = item.Unit.Do();
143 
144                                                 try
145                                                 {
146                                                     result.MoveNext();
147                                                 }
148                                                 catch (Exception ex)
149                                                 {
150                                                    
151                                                     ErrorHandle(item.Unit, ex);
152 
153                                                     Units.Remove(item);
154 
155                                                     break;
156                                                 }
157 
158                                                 item.UnitResult = result;
159                                             }
160                                             else
161                                             {
162                                                 if (item.UnitResult.Current.IsCanceled || item.UnitResult.Current.IsCompleted || item.UnitResult.Current.IsFaulted)
163                                                 {
164                                                     var nextResult = true;
165                                                     try
166                                                     {
167                                                         nextResult = item.UnitResult.MoveNext();
168                                                     }
169                                                     catch (Exception ex)
170                                                     {
171                                                         ErrorHandle(item.Unit, ex);
172 
173                                                         Units.Remove(item);
174 
175                                                         break;
176                                                     }
177                                                     if (!nextResult)
178                                                     {
179 
180                                                         Units.Remove(item);
181 
182                                                         break;
183                                                     }
184                                                 }
185                                             }
186                                         }
187                                     }
188 
189 
190                                     lock (this)
191                                     {
192                                         if (!_continue)
193                                         {
194                                             _running = false;
195                                             break;
196                                         }
197                                     }
198                                 }
199 
200 
201 
202                         });
203                     
204                 }
205 
206 
207             }
208 
209 
210 
211 
212         }
213     }

主程序调用

 1 class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             //错误处理
 6             Action<ICoroutineUnit, Exception> errorHandle = (unit, ex) =>
 7                 {
 8                     var response = ((HttpAction)unit).Response;
 9                     response.ContentType = "text/html";
10                     string str = "访问出错,错误原因:" + ex.ToString();
11                     var bytes = UTF8Encoding.UTF8.GetBytes(str);
12                     response.OutputStream.Write(bytes, 0, bytes.Length);
13                     response.OutputStream.Close();
14                 };
15             //容器初始化
16              ICoroutineContainer coroutineContainerMultipleAuto = new CoroutineContainerMultipleAuto(2, errorHandle);
17              coroutineContainerMultipleAuto.Run();
18 
19             //监听
20              HttpListener listener = new HttpListener();
21 
22              listener.Start();
23              listener.Prefixes.Add("http://localhost:8000/");
24 
25             while (true)
26             {
27                 var httpContext = listener.GetContext();
28                 //创建Http请求的协程单元
29                 HttpAction action = new HttpAction(httpContext.Request, httpContext.Response);
30                 //注册分发协程单元
31                 coroutineContainerMultipleAuto.Register(action);
32             }
33              
34 
35         }
36 
37 
38     }

程序执行后,

打开浏览器访问,获得结果

至此,基于自动多线程的协程简单框架完成

原文地址:https://www.cnblogs.com/rhwleo/p/6853830.html