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

简单的实现代码就是:

//代码一
new Thread(()=>{
//do something
}).Start();

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

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

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

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

它的作用就是将一些操作放入当前线程之外的另外一个线程中运行,它的用法非常easy:

//代码二
ThreadPool.QueueUserWorkItem(stat => {
//do something
}, null);

它相对代码一的长处是会利用已经创建过的空暇的线程,假设没有空暇就排队,而不会盲目的一直创建下去。

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

    public class BackgroundTasks
{
private class TaskEntity
{
public TaskEntity(Action<object> func, object data)
{
this.Function = func;
this.Data = data;
}
public Action<object> Function;
public object Data;
}
static Queue<TaskEntity> list = new Queue<TaskEntity>(); static BackgroundTasks()
{
Thread th = new Thread(RunTask);
th.IsBackground = true;
th.Start();
}
static void RunTask()
{
while (true)
{
if (list.Count==0)
{
Thread.Sleep(1000);
}
else
{
TaskEntity entity;
lock (list)
{
entity = list.Dequeue();
}
try
{
entity.Function(entity.Data);
}
catch { }
Thread.Sleep(10);
}
}
} public static void Add(Action<object> func, object data)
{
lock (list)
{
list.Enqueue(new TaskEntity(func, data));
}
} }

该类的使用非常easy:

BackgroundTasks.Add((obj)=>{

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

}, DateTime.Now);

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

    public class BackgroundTasks<T>
{
private Action<T> Function; private Queue<T> list = new Queue<T>(); public BackgroundTasks(Action<T> func)
{
this.Function = func; Thread th = new Thread(RunTask);
th.IsBackground = true;
th.Start();
}
private void RunTask()
{
while (true)
{
if (list.Count == 0)
{
Thread.Sleep(1000);
}
else
{
T data;
lock (list)
{
data = list.Dequeue();
}
try
{
Function(data);
}
catch { }
Thread.Sleep(10);
}
}
} public void Add(T data)
{
lock (list)
{
list.Enqueue(data);
}
} }

调用演示样例:

var bg = new BackgroundTasks<Blog>((blog) => {
Console.WriteLine(blog.BlogId);
});
int i = 0;
while (i++ < 1000)
{
bg.Add(new Blog() { BlogId = i });
}

这个设计既攻克了异步运行,又攻克了占用资源的问题。

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

不管怎么,这样的设计还是适用于非常多“普通情况”。

ThreadPool.QueueUserWorkItem的性能问题的更多相关文章

  1. ThreadPool.QueueUserWorkItem的用法

    代码: ThreadPool.SetMaxThreads(, ); ThreadPool.QueueUserWorkItem((obj) => { MessageBox.Show("执 ...

  2. 多线程操作(ThreadPool.QueueUserWorkItem

    主线程: private void GetPolicy_Load(object sender, EventArgs e) { ////ThreadPool.QueueUserWorkItem(new ...

  3. Parallel.ForEach , ThreadPool.QueueUserWorkItem

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  4. C# 多线程处理相关说明: WaitHandle,waitCallback, ThreadPool.QueueUserWorkItem

    class TestThread { static void Main() { //使用WaitHandle静态方法阻止一个线程,直到一个或多个同步对象接收到信号 WaitHandle[] waitH ...

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

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

  6. ThreadPool.QueueUserWorkItem引发的血案,线程池异步非正确姿势导致程序闪退的问题

    ThreadPool是.net System.Threading命名空间下的线程池对象.使用QueueUserWorkItem实现对异步委托的先进先出有序的回调.如果在回调的方法里面发生异常则应用程序 ...

  7. 多线程实现Thread.Start()与ThreadPool.QueueUserWorkItem两种方式对比

    Thread.Start(),ThreadPool.QueueUserWorkItem都是在实现多线程并行编程时常用的方法.两种方式有何异同点,而又该如何取舍? 写一个Demo,分别用两种方式实现.观 ...

  8. 合理使用线程池 ThreadPool.QueueUserWorkItem()

    //==>自建线程 new Thread(() => { //线程任务 Console.WriteLine(Thread.CurrentThread.ManagedThreadId); } ...

  9. 难道调用ThreadPool.QueueUserWorkItem()的时候,真是必须调用Thread.Sleep(N)吗?

    开门见山,下面的例子中通过调用ThreadPool.QueueUserWorkItem(WaitCallback callBack, object state)的方式实现异步调用: 1: class ...

随机推荐

  1. 云服务和虚拟机的预留 IP 地址

    大家好! 我很高兴地向大家宣布,云服务和虚拟机的预留 IP 地址将自 2014年 5月 12日起正式发布.在这篇博客中,我们将演示如何管理预留 IP.将预留 IP 与云服务和虚拟机关联.定价模型和一些 ...

  2. oracle 命令创建用户 、授权、数据库导入、导出

    最近在使用oracle,经常要导入导出数据,命令很简单,却经常忘记,所以记下来.. drop user yfplss cascade;--登录system用户删除已存在的用户名,该用户下的所有东西都被 ...

  3. TCP协议三次握手过程分析

    TCP(Transmission Control Protocol) 传输控制协议 TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接: 位码即tcp标志位,有6种标 ...

  4. data按钮

    1.加载状态 通过按钮(Button)插件,您可以添加进一些交互,比如控制按钮状态,或者为其他组件(如工具栏)创建按钮组. 如需向按钮添加加载状态,只需要简单地向 button 元素添加 data-l ...

  5. bootstrap-js(1)模态框

    1.禁止动画效果 如果你不需要模态框弹出时的动画效果(淡入淡出效果),删掉 .fade 类即可.一般还是不要去动这个,最多自己换个类名在写其他样式,不然你会头大的. <div class=&qu ...

  6. 扩展第三方DropDownMenu

    找工作之际,静下心总结工作中的想法. 我的简书 原来的效果 Paste_Image.png #解析结构 导读 想要扩展首先我需要执行下面几个步骤 1.fork DropDownMenu到自己的gith ...

  7. ASP.NET仿新浪微博下拉加载更多数据瀑布流效果

    闲来无事,琢磨着写点东西.貌似页面下拉加载数据,瀑布流的效果很火,各个网站都能见到各式各样的展示效果,原理大同小异.于是乎,决定自己写一写这个效果,希望能给比我还菜的菜鸟们一点参考价值. 在开始之前, ...

  8. Http请求头中的字段理解

    1.Accept属于请求头, Content-Type属于实体头. Http报头分为通用报头,请求报头,响应报头和实体报头. 请求方的http报头结构:通用报头|请求报头|实体报头 响应方的http报 ...

  9. c++中类模版中的static数据成员的定义

    这个有点绕. 如下: template <typename T> class A{ ......... static std::allocate<T> alloc_; }; t ...

  10. php7 install script

    ./configure --prefix=/home/admin/local/php7 --with-gd=/home/admin/local/libgd-2.1.1/ --with-jpeg-dir ...