大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE稳定放心使用
在WEB开发中,为了减少页面等待时间提高用户体验,我们往往会把一些浪费时间的操作放到新线程中在后台运行。
简单的实现代码就是:
//代码一
new Thread(()=>{
//do something
}).Start();
但是对于一个请求量大的网址这样做是很不现实的——每一个操作都要开启一个新线程,最终会因CPU不堪重负而使网站挂掉。
更好的做法是使用线程队列。
对于线程队列 ThreadPool.QueueUserWorkItem 很多人应该都不陌生,下边看微软的解释:
将方法排入队列以便执行,并指定包含该方法所用数据的对象。此方法在有线程池线程变得可用时执行。
它的作用就是将一些操作放入当前线程之外的另外一个线程中执行,它的使用方法很简单:
//代码二
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));
}
}
}
该类的使用很简单:
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导致很多任务还没有被执行就被丢弃。
无论怎么,这种设计还是适用于很多“一般情况”。
作者:朱会震
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/189800.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...