之前参照某位高手的代码(忘了是哪一位了,不好意思),试着到.net去模拟一个任务线程池.
主要的思路如下:
1、创建一个单例对象,这个单例对象上面有两个字典变量,两个队列变量,分别保存所有线程的引用, 工作队列,还有正在执行的线程队列,空闲的线程队列.
2、在这个单例对象里,还设一个主线程,以一定时间轮询更新以上四个变量的信息。
3、线程的主要任务是执行相关sql语句,执行完后,或生成文件,或执行任务脚本程序,有点类型oracle的job,但是比它更灵活一点。
以上是代码片断
1 public class TaskJobPool : IDisposable 2 { 3 4 public Dictionary<int, JobEntity> poolDic; //所有的线程池线的所有线程 5 public Queue<TaskInst> jobQueue; //待执行的任务队列 6 public Dictionary<int, JobEntity> workJobQueue; //正在工作队列 7 public Queue<JobEntity> freeQueue; //空闲队列 8 9 10 int minPoolSize = 10; //最小线程数 11 int maxPoolSize = 50;//最大线程数 12 int incrementPoolSize = 5; //当活动线程不足的时候新增线程的增量 13 14 //设置最大线程数 15 16 public void SetMaxSize(int Value) 17 { 18 lock (this) 19 { 20 maxPoolSize = Value; 21 } 22 23 } 24 25 //设置最小线程数 26 public void SetMinSize(int Value) 27 { 28 lock (this) 29 { 30 minPoolSize = Value; 31 } 32 33 } 34 35 //设置增量 36 public void SetIncrement(int Value) 37 { 38 lock (this) 39 { 40 incrementPoolSize = Value; 41 } 42 43 } 44 45 private TaskJobPool() 46 { 47 // 48 //TODO: 在此处添加构造函数逻辑 49 // 50 poolDic = new Dictionary<int, JobEntity>(); 51 jobQueue = new Queue<TaskInst>(); 52 workJobQueue = new Dictionary<int, JobEntity>(); 53 freeQueue = new Queue<JobEntity>(); 54 55 56 57 } 58 59 60 //任务队列 61 private static TaskJobPool _TaskJobPool = null; 62 private static readonly object padlock = new object(); 63 64 public static TaskJobPool GetInstance() 65 { 66 if (_TaskJobPool == null) 67 { 68 lock (padlock) 69 { 70 71 72 _TaskJobPool = (TaskJobPool)WebCache.GetWebCache().GetApplicationCache("TaskJobPool"); 73 74 75 76 77 78 if (_TaskJobPool == null) 79 { 80 _TaskJobPool = new TaskJobPool(); 81 WebCache.GetWebCache().SetApplicationCache("TaskJobPool", _TaskJobPool); 82 83 } 84 } 85 } 86 return _TaskJobPool; 87 88 } 89 90 //线程执行完毕后的触发事件 (相当于旧线程池的轮询主方法) 91 92 93 public void ReStartService() 94 { 95 try 96 { 97 Dispose(); 98 99 poolDic.Clear(); 100 workJobQueue.Clear(); 101 jobQueue.Clear(); 102 freeQueue.Clear(); 103 104 if (mainThread != null) 105 { 106 Thread th = mainThread; 107 th.Abort(); 108 mainThread = null; 109 } 110 StartService(); 111 } 112 catch (Exception e) 113 { 114 } 115 116 } 117 118 public void StartService() 119 { 120 try 121 { 122 JobEntity je = null; 123 //先创建最小线程数的线程 124 125 if (poolDic.Count == 0) 126 { 127 for (int i = 0; i < minPoolSize; i++) 128 { 129 if (poolDic.ContainsKey(i + 1)) break; 130 je = new JobEntity(); 131 je.Key = i + 1; 132 //注册线程完成时触发的事件 133 je.WorkComplete += new Action<JobEntity>(j_WorkComplete); 134 //加入到所有线程的字典中 135 poolDic.Add(i + 1, je); 136 //因为还没加入具体的工作委托就先放入空闲队列 137 freeQueue.Enqueue(je); 138 139 140 } 141 } 142 143 Refresh(); 144 StartTask(); 145 146 147 if (!TaskJobPool.getThread().IsAlive) 148 TaskJobPool.getThread().Start(); 149 } 150 catch (Exception e) { } 151 152 } 153 154 155 static Thread mainThread = null; 156 public static Thread getThread() 157 { 158 try 159 { 160 if (mainThread == null) 161 { 162 mainThread = new Thread(new ThreadStart(TaskJobPool.GetInstance().MasterScanMethod)); 163 mainThread.IsBackground = true; 164 } 165 166 167 } 168 catch (Exception e) { } 169 return mainThread; 170 } 171 172 173 public void MasterScanMethod() 174 { 175 176 while ( true) 177 { 178 Refresh(); 179 StartTask(); 180 Thread.Sleep(300000); 181 } 182 183 //删除过期的表 184 TaskInstTableImp titi = new TaskInstTableImp(0, "gsm"); 185 titi.DeleteTaskTempTable(0); 186 187 } 188 189 190 public void StopService() 191 { 192 193 foreach (JobEntity j in poolDic.Values) 194 { 195 196 //关闭所有的线程 197 //using (j) { j.Close(); } 198 j.Close(); 199 200 } 201 202 203 if (mainThread != null) 204 { 205 Thread th = mainThread; 206 th.Abort(); 207 mainThread = null; 208 } 209 210 } 211 212 213 public void Refresh() //刷新任务单数据 214 { 215 216 lock (new object()) 217 { 218 //刷新任务队列清单 219 TaskInstImp task_inst_imp = new TaskInstImp(0, "gsm"); 220 IList<TaskInst> tasks = task_inst_imp.GetExecTartgetTask(); 221 foreach (TaskInst entity in tasks) 222 { 223 if (jobQueue.Where<TaskInst>(p => p.Id == entity.Id).ToList<TaskInst>().Count == 0) //如果作务队列有的,就不加进去 224 jobQueue.Enqueue(entity); 225 } 226 227 } 228 229 } 230 231 232 public void StartTask() //启动任务单 233 { 234 235 236 TaskInstImp task_inst_imp = new TaskInstImp(0, "gsm"); 237 238 239 lock (typeof(TaskJobPool)) 240 { 241 while (jobQueue.Count > 0) //如果有待处理的任务单 242 { 243 //出列 244 TaskInst task = jobQueue.Dequeue(); 245 JobEntity je = null; 246 if (freeQueue.Count > 0) //存在空闲线程 247 { 248 je = freeQueue.Dequeue(); 249 } 250 else //不存在空闲线程就新增一个 251 { 252 if (poolDic.Count >= minPoolSize && poolDic.Count < maxPoolSize) 253 { 254 255 je = new JobEntity(); 256 257 //job ID号拾漏 258 for (int freeI = 1; freeI < maxPoolSize; freeI++) 259 { 260 if (!poolDic.ContainsKey(freeI)) 261 { 262 je.Key = freeI; 263 break; 264 } 265 266 } 267 //je.Key = i + 1; 268 //注册线程完成时触发的事件 269 je.WorkComplete += new Action<JobEntity>(j_WorkComplete); 270 //加入到所有线程的字典中 271 poolDic.Add(je.Key, je); 272 273 } 274 else 275 break; 276 } 277 278 je.contextdata = task.Id; 279 //任务状态置一下,否则会被重复执行 280 TaskInst task_inst = task_inst_imp.Load(task.Id); 281 task_inst.State = "A"; 282 task_inst.UpdateDate = DateTime.Now; 283 task_inst_imp.Update(task_inst); 284 285 286 287 workJobQueue.Add(je.Key, je); 288 //唤醒线程开始执行 289 je.Active(); 290 291 292 293 } 294 295 296 297 Queue<JobEntity> t = new Queue<JobEntity>(); 298 while (freeQueue.Count > 0) 299 { 300 301 JobEntity tt = freeQueue.Dequeue(); 302 303 if (tt.Key > minPoolSize) 304 { 305 tt.contextdata = null; 306 poolDic.Remove(tt.Key); 307 tt.Dispose(); 308 } 309 else 310 t.Enqueue(tt); 311 } 312 313 while (t.Count > 0) 314 { 315 freeQueue.Enqueue(t.Dequeue()); 316 } 317 318 319 320 } 321 foreach (JobEntity j in workJobQueue.Values.ToList<JobEntity>().Where<JobEntity>(p => !p.Working).ToList<JobEntity>()) 322 { 323 324 j.Active(); 325 326 } 327 328 } 329 330 331 void j_WorkComplete(JobEntity obj) 332 { 333 334 lock (this) 335 { 336 //本线程执行完毕,需要从工作字典集合中剔除 337 workJobQueue.Remove(obj.Key); 338 //线程关闭 339 obj.Close(); 340 ////线程池状态更新 341 //poolDic.Remove(obj.Key); 342 //poolDic.Add(obj.Key, obj); 343 344 345 //刷新工单池信息 346 Refresh(); 347 348 //当任务队列没有单时,就将额外增加的线程注销掉,以减轻系统负载 349 //if (jobQueue.Count == 0 && freeQueue.Count > minPoolSize) 350 //{ 351 //线程标识大于最小线程数时,注销 352 if (jobQueue.Count == 0 && obj.Key > minPoolSize) 353 { 354 poolDic.Remove(obj.Key); 355 obj.contextdata = null; 356 obj.Dispose(); 357 } 358 else 359 { 360 // 如果线程标识没有超过最小线程数就把线程从工作字典放入空闲队列 361 obj.contextdata = null; 362 freeQueue.Enqueue(obj); 363 } 364 //} 365 366 StartTask(); 367 368 369 } 370 371 } 372 public void Dispose() 373 { 374 375 foreach (JobEntity j in poolDic.Values) 376 { 377 378 //关闭所有的线程 379 380 //using (j) { j.Dispose(); } 381 j.Dispose(); 382 383 } 384 385 poolDic.Clear(); 386 workJobQueue.Clear(); 387 jobQueue.Clear(); 388 freeQueue.Clear(); 389 390 if (mainThread != null) 391 { 392 Thread th = mainThread; 393 th.Abort(); 394 mainThread = null; 395 } 396 397 398 } 399 400 }
现在有个问题:这个线程池,在小任务执行,还可以多线程同时执行,但是时间一长,如三小时后,上面的四个变量变为空,了也就是说:差不多一定时间表后,似乎.net会回收资源,造成相信关变量被初始化,为啥会出现这种情况, 烦请大虾指教.
话说能不能给线程赋一个方法让他去执行?而不是新建线程的时候指定方法?
至于资源回收,那是iis的应用程序池回收机制.你可以把他关了.默认是20分钟没有请求就会回收应用程序池
线程赋予一个方法?能否具体举例?
另外,如果把iis的应用程序池回收机制关了,那么正常的请求那不是不会正常回收了,那么时候系统资源会不会用尽?
@快乐是短暂的: 不然你的线程池是怎么实现线程重用的,就是一个线程执行完毕后,你怎么让他重新打开?
ASP.NET是有GC的,要是因为把IIS回收关了系统资源就用尽了.那说明你的代码有问题
@吴瑞祥:
1、一个线程执行完毕后,通过线程锁暂停。实际上,我线程执行方法是固定的,变化的只是传入的作业标识。只不过线程执行完成后,需要对对应的连接池进行清理。
2、ASP.NET是有GC的,要是因为把IIS回收关了系统资源就用尽了.那说明你的代码有问题
----在外面有写一个定时刷新网页的方式,会自动重启iis进程,任务退出也有记录断点,重启后会继续执行