ThreadPool. QueueUserWorkItem performance problem, queueuserworkitem
Reference: http://blog.csdn.net/sq_zhuyi/article/details/6869661
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 ();View Code
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 );View Code
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:
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 else30 {31 TaskEntity entity; 32 lock (list) 33 {34 entity = list. dequeue (); 35} 36 try37 {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}View Code
This class is easy to use:
BackgroundTasks. Add (obj) => {Console. WriteLine ("this task was added at: {0}", obj as DateTime) ;}, DateTime. Now );
Another "instance version" is to create a task queue for each method:
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 else24 {25 T data; 26 lock (list) 27 {28 data = list. dequeue (); 29} 30 try31 {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}View Code
Blog type:
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 ;}}}View Code
Call example:
// Method 2: 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 = "James"}); bg. add (new Blog () {BlogId = 1001, BlogName = ""});View Code
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 ".