In web development, in order to reduce the page wait time and improve the user experience, we usually put some time-wasting operations in the new thread to run in the background.
The simple implementation code is:
// Code 1 new thread () =>{// do something}). Start ();
However, it is unrealistic to do this for a website with a large number of requests-each operation must start a new thread, and the website will eventually be suspended due to the CPU overload.
A better way is to use a thread queue.
Many people should be familiar with thread queue threadpool. queueuserworkitem. Let's look at Microsoft's explanation below:
Queues methods for execution and specifies the objects that contain the data used by the method. This method is executed when a thread pool thread becomes available.
Its function is to put some operations into another thread other than the current thread for execution. Its usage is simple:
// Code 2 threadpool. queueuserworkitem (STAT =>{// do something}, null );
Compared with code 1, it uses Idle threads that have been created. If there is no idle thread, it queues without blindly creating it.
But it does not get rid of the problem of "Creating a New thread": too many threads will occupy more resources. From this we can hardly imagine why we don't have to create a queue ourselves so that they can be executed one by one in the same thread? In this regard, I wrote a simple implementation class:
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)); } } }
This class is easy to use:
Backgroundtasks. Add (OBJ) => {
Console. writeline ("the task was added at {0}", OBJ as datetime );
}, Datetime. Now );
Another "instance version" is to create a task queue for each method:
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); } } }
Call example:
var bg = new BackgroundTasks<Blog>((blog) => { Console.WriteLine(blog.BlogId); });int i = 0;while (i++ < 1000){ bg.Add(new Blog() { BlogId = i });}
This design solves both asynchronous execution and resource occupation.
But there is no perfect thing in the world, and the same is true for the Code. Because the tasks in the queue are executed in a single thread, some tasks may be executed after a long time, or restart IIS to discard many tasks that have not been executed.
In any case, this design still applies to many "general situations ".