在WEB开发中,为了减少页面等待时间提高用户体验,我们往往会把一些浪费时间的操作放到新线程中在后台运行。

简单的实现代码就是:

[csharp] view plaincopy print?
  1. //代码一
  2. new Thread(()=>{
  3. //do something
  4. }).Start();

但是对于一个请求量大的网址这样做是很不现实的——每一个操作都要开启一个新线程,最终会因CPU不堪重负而使网站挂掉。

更好的做法是使用线程队列。

对于线程队列 ThreadPool.QueueUserWorkItem 很多人应该都不陌生,下边看微软的解释:

将方法排入队列以便执行,并指定包含该方法所用数据的对象。此方法在有线程池线程变得可用时执行。

它的作用就是将一些操作放入当前线程之外的另外一个线程中执行,它的使用方法很简单:

[csharp] view plaincopy print?
  1. //代码二
  2. ThreadPool.QueueUserWorkItem(stat => {
  3. //do something
  4. }, null);

它相对代码一的优点是会利用已经创建过的空闲的线程,如果没有空闲就排队,而不会盲目的一直创建下去。

但是它并没有摆脱“创建新线程”的问题:过多的线程会占用更多的资源。由此我们不难想到,我们为什么不自己搞个队列,让它们在同一个线程中逐个执行?对此,我写了个简单的实现类:

[csharp] view plaincopy print?
  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. static BackgroundTasks()
  15. {
  16. Thread th = new Thread(RunTask);
  17. th.IsBackground = true;
  18. th.Start();
  19. }
  20. static void RunTask()
  21. {
  22. while (true)
  23. {
  24. if (list.Count==0)
  25. {
  26. Thread.Sleep(1000);
  27. }
  28. else
  29. {
  30. TaskEntity entity;
  31. lock (list)
  32. {
  33. entity = list.Dequeue();
  34. }
  35. try
  36. {
  37. entity.Function(entity.Data);
  38. }
  39. catch { }
  40. Thread.Sleep(10);
  41. }
  42. }
  43. }
  44. public static void Add(Action<object> func, object data)
  45. {
  46. lock (list)
  47. {
  48. list.Enqueue(new TaskEntity(func, data));
  49. }
  50. }
  51. }

该类的使用很简单:

BackgroundTasks.Add((obj)=>{

Console.WriteLine("这个任务的添加时间是:{0}", obj as DateTime);

}, DateTime.Now);

还有一个“实例版”的,就是针对每个方法,分别创建一个任务队列:

[csharp] view plaincopy print?
  1. public class BackgroundTasks<T>
  2. {
  3. private Action<T> Function;
  4. private Queue<T> list = new Queue<T>();
  5. public BackgroundTasks(Action<T> func)
  6. {
  7. this.Function = func;
  8. Thread th = new Thread(RunTask);
  9. th.IsBackground = true;
  10. th.Start();
  11. }
  12. private void RunTask()
  13. {
  14. while (true)
  15. {
  16. if (list.Count == 0)
  17. {
  18. Thread.Sleep(1000);
  19. }
  20. else
  21. {
  22. T data;
  23. lock (list)
  24. {
  25. data = list.Dequeue();
  26. }
  27. try
  28. {
  29. Function(data);
  30. }
  31. catch { }
  32. Thread.Sleep(10);
  33. }
  34. }
  35. }
  36. public void Add(T data)
  37. {
  38. lock (list)
  39. {
  40. list.Enqueue(data);
  41. }
  42. }
  43. }

调用示例:

[csharp] view plaincopy print?
  1. var bg = new BackgroundTasks<Blog>((blog) => {
  2. Console.WriteLine(blog.BlogId);
  3. });
  4. int i = 0;
  5. while (i++ < 1000)
  6. {
  7. bg.Add(new Blog() { BlogId = i });
  8. }

这个设计既解决了异步执行,又解决了占用资源的问题。

但是世界上没有完美的东西,代码也是如此,由于队列中的任务是单线程执行,可能会导致某些任务在很长时间后才会被执行到,或者重启IIS导致很多任务还没有被执行就被丢弃。

无论怎么,这种设计还是适用于很多“一般情况”。

ThreadPool.QueueUserWorkItem的性能问题相关推荐

  1. ThreadPool.QueueUserWorkItem的用法

    代码: ThreadPool.SetMaxThreads(100, 100); ThreadPool.QueueUserWorkItem((obj) => {MessageBox.Show(&q ...

  2. ThreadPool.QueueUserWorkItem的用法,带参数和不带参数

    1,不带参数 ThreadPool.QueueUserWorkItem(delegate { PostDataWhenLoadData(); }); pubic static void PostDat ...

  3. ThreadPool.QueueUserWorkItem

    ThreadPool.QueueUserWorkItem(_ => { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(&q ...

  4. ThreadPool.QueueUserWorkItem启动慢

    一.问题描述 ThreadPool.QueueUserWorkItem启动慢,在项目过程中发现当线程数量达到一定量的时候发线线程启动速度 慢,影响了正常的实时性业务. 二.解决方法 加入  Threa ...

  5. C# ThreadPool.QueueUserWorkItem()之线程池异步

    项目中有大文件传输需求,用户在网页端填好某个IP下的共享目录,服务端通过所填路径检测共享目录下的文件以供用户选择待传输的文件, 用户勾选相应文件后点击提交,服务端遂开始执行文件传输.所有的逻辑过程都在 ...

  6. .NET线程方法:Thread.Start()与ThreadPool.QueueUserWorkItem()

    .NET提供了几种创建线程并启动它的方法.那么,有两种方法(基本上): (1)使用System.Threading.Thread类. Thread curr = new Thread(myfuncti ...

  7. C#ThreadPool.QueueUserWorkItem实例

    今天学习线程池的时候发现,网上能搜到的都是很久以前的文档了,大家都是照搬过去,有没有考证都是问题. 经过测试结果已经和他们说的不一样了,比如 <span style="white-sp ...

  8. C#线程池ThreadPool.QueueUserWorkItem接收线程执行的方法返回值

    最近在项目中需要用到多线程,考虑了一番,选择了ThreadPool,我的需求是要拿到线程执行方法的返回值, 但是ThreadPool.QueueUserWorkItem的回调方法默认是没有返回值的,搜 ...

  9. ThreadPool.QueueUserWorkItem 方法 (WaitCallback)

    说明:将方法排入队列以便执行,WaitCallback,表示要执行的方法.如果将方法成功排入队列,则为 true:否则为 false. 示例:addtest方法需要比较长的时间来响应,因此在butto ...

最新文章

  1. Python网络编程1--笔记
  2. 第八篇、盒子模型和距中的设置方法
  3. Flask实战2问答平台-登录限制(装饰器)
  4. 黄聪: 50 个 Bootstrap 插件
  5. DNS 访问 Service - 每天5分钟玩转 Docker 容器技术(138)
  6. vue 带全选和多选的表格怎么写_EXCEL五分钟,批量制作带照片的工地出入证
  7. sql服务器时间不正确,使用更改 CPU 频率的实用工具或技术时,SQL Server 计时值可能不正确...
  8. 2018-2019-2 20175311 实验一《Java开发环境的熟悉》实验报告
  9. IOS多类型Cell的tableView实现
  10. php mysql访问不,php不能访问mysql怎么办
  11. 基于Visual C++2010与windows7 SDK开发传感器应用(触觉传感器,温度传感器等等)
  12. java中装饰器_java设计模式之装饰器模式以及在java中作用
  13. DSP 增强型脉宽调制ePWM
  14. jquery.cookie.js 每天首次打开页面时弹出广告
  15. numpy.ndarray中对于字符串的处理
  16. 力扣 714. 买卖股票的最佳时机含手续费
  17. Open vSwitch ETHERNET相关字段详解(eth_src/dl_src、eth_dst/dl_dst、eth_type/dl_type)
  18. MPI矩阵向量乘法代码《并行程序设计导论》
  19. CSV格式的文件与EXCEL文件的区别
  20. NR 5G 无线协议架构

热门文章

  1. java preference xml,java-将PreferenceScreen添加到linearlayout
  2. 2023年咸阳市《网络搭建与应用》专业技能大赛试题
  3. 社群众筹之后,社群新零售结合智慧商业联盟是必然趋势
  4. B树与B+树的区别!!
  5. 如何备份和恢复iOS应用程序的数据和设置
  6. 居中到底有多少种方法
  7. linux bootloader原理,Bootloader原理详解
  8. 【深度学习】R-CNN 论文解读及个人理解
  9. 如何使用 Xshell 连接 Linux 服务器
  10. Windows10 安装 WSL2