标签:
引用:http://blog.csdn.net/sq_zhuyi/article/details/6869661
在WEB开发中,为了减少页面等待时间提高用户体验,我们往往会把一些浪费时间的操作放到新线程中在后台运行。
简单的实现代码就是:
//代码一 new Thread(()=>{ //do something }).Start();
但是对于一个请求量大的网址这样做是很不现实的——每一个操作都要开启一个新线程,最终会因CPU不堪重负而使网站挂掉。
更好的做法是使用线程队列。
对于线程队列 ThreadPool.QueueUserWorkItem 很多人应该都不陌生,下边看微软的解释:
将方法排入队列以便执行,并指定包含该方法所用数据的对象。此方法在有线程池线程变得可用时执行。
它的作用就是将一些操作放入当前线程之外的另外一个线程中执行,它的使用方法很简单:
//代码二 ThreadPool.QueueUserWorkItem(stat => { //do something }, null);
它相对代码一的优点是会利用已经创建过的空闲的线程,如果没有空闲就排队,而不会盲目的一直创建下去。
但是它并没有摆脱“创建新线程”的问题:过多的线程会占用更多的资源。由此我们不难想到,我们为什么不自己搞个队列,让它们在同一个线程中逐个执行?对此,我写了个简单的实现类:
1 public class BackgroundTasks 2 { 3 private class TaskEntity 4 { 5 public TaskEntity(Action<object> func, object data) 6 { 7 this.Function = func; 8 this.Data = data; 9 } 10 public Action<object> Function; 11 public object Data; 12 } 13 static Queue<TaskEntity> list = new Queue<TaskEntity>(); 14 15 static BackgroundTasks() 16 { 17 Thread th = new Thread(RunTask); 18 th.IsBackground = true; 19 th.Start(); 20 } 21 static void RunTask() 22 { 23 while (true) 24 { 25 if (list.Count == 0) 26 { 27 Thread.Sleep(1000); 28 } 29 else 30 { 31 TaskEntity entity; 32 lock (list) 33 { 34 entity = list.Dequeue(); 35 } 36 try 37 { 38 entity.Function(entity.Data); 39 } 40 catch { } 41 Thread.Sleep(10); 42 } 43 } 44 } 45 46 public static void Add(Action<object> func, object data) 47 { 48 lock (list) 49 { 50 list.Enqueue(new TaskEntity(func, data)); 51 } 52 } 53 54 }
该类的使用很简单:
BackgroundTasks.Add((obj)=>{ Console.WriteLine("这个任务的添加时间是:{0}", obj as DateTime); }, DateTime.Now);
还有一个“实例版”的,就是针对每个方法,分别创建一个任务队列:
1 public class BackgroundTasks01<T> 2 { 3 private Action<T> Function; 4 5 private Queue<T> list = new Queue<T>(); 6 7 public BackgroundTasks01(Action<T> func) 8 { 9 this.Function = func; 10 11 Thread th = new Thread(RunTask); 12 th.IsBackground = true; 13 th.Start(); 14 } 15 private void RunTask() 16 { 17 while (true) 18 { 19 if (list.Count == 0) 20 { 21 Thread.Sleep(1000); 22 } 23 else 24 { 25 T data; 26 lock (list) 27 { 28 data = list.Dequeue(); 29 } 30 try 31 { 32 Function(data); 33 } 34 catch { } 35 Thread.Sleep(10); 36 } 37 } 38 } 39 40 public void Add(T data) 41 { 42 lock (list) 43 { 44 list.Enqueue(data); 45 } 46 } 47 48 }
blog类:
class Blog { private int _blogId = 0; public int BlogId { get { return _blogId; } set { _blogId = value; } } private string _blogName = ""; public string BlogName { get { return _blogName; } set { _blogName = value; } } }
调用示例:
//方法二: var bg = new BackgroundTasks01<Blog>((blog) => { Console.WriteLine("BlogName:{0},BlogId:{1}", blog.BlogName, blog.BlogId); }); int i = 0; while (i++ < 100) { bg.Add(new Blog() { BlogId = i, BlogName = "Default" }); } Console.ReadLine(); bg.Add(new Blog() { BlogId = 1000, BlogName = "张三" }); bg.Add(new Blog() { BlogId = 1001, BlogName = "李四" });
这个设计既解决了异步执行,又解决了占用资源的问题。
但是世界上没有完美的东西,代码也是如此,由于队列中的任务是单线程执行,可能会导致某些任务在很长时间后才会被执行到,或者重启IIS导致很多任务还没有被执行就被丢弃。
无论怎么,这种设计还是适用于很多“一般情况”。
ThreadPool.QueueUserWorkItem的性能问题
标签:
原文地址:http://www.cnblogs.com/xzxBlog/p/xzxBlog.html