关键词:
创建多线程操作是非常昂贵的,所以每个运行时间非常短的操作,创建多线程进行操作,可能并不能提高效率,反而降低了效率。
如果你有非常多的执行时间非常短的操作,那么适合作用线程池来提高效率,而不是自行创建多线程。
线程池,就是我们先分配一些资源到池子里,当我们需要使用时,则从池子中获取,用完了,再放回池子里。
.NET中的线程池是受CLR管理的,TheadTool类有一个QueueUserWorkItem静态方法,这个静态方法接受一个委托,代表用户自定义的一个异步操作,在这个方法被调用之后,委托会进入到内部队列中,如果池中没有线程,则创建一个工作线程,把第一个委托放入工作线程。如果继续放入委托,则池创建新的工作线程,直到工作线程数量达到上限。这时再放入委托,则不会创建新的工作线程,而是在队列中等待,直到有空闲的工作线程。
当线程池中所有操作都完成,而且没有新任务操作时,线程池会释放长时间不用的资源。
注意:放入线程池中的操作需要的时间要短,不要把需要长时间运行的操作放入线程池中,或阻塞工作线程。这将导致性能问题和非常难以调用的问题。
在ASP.NET中使用线程池要当心,ASP.NET中的线程池是一个共用线程池,如果线程池中的工作线程都用完了,则会造成WEB服务器对正常的HTTP请求无法提供服务。
一、 线程池中调用委托
1.代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace ThreadPoolDemo { public delegate string ThreadPoolRun(out int threadId); class Program { static void Main(string[] args) { Console.WriteLine("开始测试线程池-委托。。。"); int threadId = 0; ThreadPoolRun poolDele = RunThread; var t = new Thread(() => RunThread(out threadId)); t.Start(); t.Join(); Console.WriteLine("线程ID {0} ",threadId); IAsyncResult r = poolDele.BeginInvoke(out threadId, Callback, "在线程池中同步调用回调函数"); string result = poolDele.EndInvoke(out threadId, r); Console.WriteLine("线程池中工作线程ID :{0}", threadId); Console.WriteLine("返回结果:{0}",result); Thread.Sleep(2000); Console.Read(); } private static void Callback(IAsyncResult r) { Console.WriteLine("开始调用回调函数。。。"); Console.WriteLine("回调函数此时的状态 :{0}",r.AsyncState); Console.WriteLine("调用此回调函数的线程是否在线程池 :{0}", Thread.CurrentThread.IsThreadPoolThread); Console.WriteLine("调用此回调函数的线程在线程池在的ID :{0}", Thread.CurrentThread.ManagedThreadId); } private static string RunThread(out int threadId) { Console.WriteLine("开始工作。。。"); Console.WriteLine("调用此回调函数的线程是否在线程池 :{0}", Thread.CurrentThread.IsThreadPoolThread); Thread.Sleep(TimeSpan.FromSeconds(2)); threadId = Thread.CurrentThread.ManagedThreadId; return string.Format("此线程在线程池在的ID :{0}", threadId); } } }
2.程序执行结果如下图。
上面的程序运行时,我们首先创建线程来执行委托操作,然后调用委托的BeginInvoke来执行回调方法,这个回调函数会在异步操作完成之后会被调用,并且会把一个自定义的值传给这个回调函数,最后我们会得到一个实现了IAsyncResult接口的result对象,当线程池的工作线程在进行工作时,允许我们继续其他操作。我们可以轮询result对象的IsCompleted属性,确定操作是否完成。也可以调用EndInvoke将IAsyncResult传给委托参数。
二、 线程池中放入异步操作
1.代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace ThreadPoolDemo { class Program { static void Main(string[] args) { Console.WriteLine("开始测试线程池-QueueUserWorkItem。。。"); const int x = 1; const int y = 2; string workState = "工作状态 2"; ThreadPool.QueueUserWorkItem(AsyncOper); Thread.Sleep(1000); ThreadPool.QueueUserWorkItem(AsyncOper,"同步状态"); Thread.Sleep(1000); ThreadPool.QueueUserWorkItem(status => { Console.WriteLine("操作状态 {0} ", status); Console.WriteLine("线程池中工作线程ID :{0}", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(TimeSpan.FromSeconds(2)); },"工作状态"); ThreadPool.QueueUserWorkItem(_ => { Console.WriteLine("操作结果x+y= {0} ,{1}", x+y,workState); Console.WriteLine("线程池中工作线程ID :{0}", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(TimeSpan.FromSeconds(2)); }, "工作状态"); Thread.Sleep(2000); Console.Read(); } private static void AsyncOper(object status) { Console.WriteLine("操作状态 :{0} ",status??"null"); Console.WriteLine("工作线程在线程池在的ID :{0}", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(2000); } } }
2.执行结果如下。程序执行了两次。
程序首先定义了一个AsyncOper方法,然后使用QueueUserWorkItem将这个方法放入线程池中,然后再次放入一个AsyncOper方法,不过这次给方法调用传一个对象。
代码中的调用Thread.sleep方法,是为了让线程池中的工作线程为新操作重用。请注意打印出来的ThradId,如果ThreadID一样则证明两个操作重用了同一个工作线程。
多线程编程学习笔记
多线程编程目录线程概述线程的创建创建线程程序线程同步守护线程线程之间的相互通讯线程池和java.util.concurrent包一、概述1.相关概念进程(Process):程序(任务)执行的过程,每个进程都有自己独立的一块内存空间,一个进程中可... 查看详情
《c++多线程编程》学习笔记(代码片段)
文章目录线程安全的对象生命期管理当析构函数遇上多线程对象的创建对象池线程同步精要互斥器(mutex)条件变量(conditionvariable)慎用读写锁多线程服务器的适合模型与常用编程模型oneloopperthread+threadpool进... 查看详情
多线程编程学习笔记——线程同步
接上文多线程编程学习笔记-基础(一)接上文多线程编程学习笔记-基础(二)接上文多线程编程学习笔记-基础(三) 就如上一篇文章(多线程编程学习笔记-基础(三))中的示例代码十,一样如果... 查看详情
多线程编程学习笔记-基础
接上文多线程编程学习笔记-基础(一)接上文多线程编程学习笔记-基础(二)九、向线程传递参数 1.代码如下。 usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading;//引入线程usingSystem.Diagnostics;na... 查看详情
多线程编程学习笔记——线程同步
接上文 多线程编程学习笔记——线程同步(一)接上文多线程编程学习笔记——线程同步(二) 七、使用Barrier类Barrier类用于组织多个线程及时在某个时刻会面,其提供一个回调函数,每次线程调用了Sig... 查看详情
java多线程高并发学习笔记——深入理解线程池
线程池最核心的一个类:ThreadPoolExecutor.看一下该类的构造器: publicThreadPoolExecutor(intparamInt1,intparamInt2,longparamLong,TimeUnitparamTimeUnit,BlockingQueue<Runnable>paramBlockingQueue){this(paramInt1,paramIn 查看详情
多线程编程学习五(线程池的创建)
...bsp;a、每次NewThread新建对象性能差。 b、线程缺乏统一的管理,可能无限制的新建线程,相互之间竞争,极可能占用过多的系统资源导致死机或者OOM。 c、缺乏更多功能,如定时执行、定期执行... 查看详情
多线程编程学习笔记——任务并行库
接上文多线程编程学习笔记——任务并行库(一)接上文 多线程编程学习笔记——任务并行库(二) 六、 实现取消选项 本示例学习如何实现基于Task的异步操... 查看详情
多线程编程学习笔记——使用并发集合
接上文多线程编程学习笔记——使用并发集合(一)接上文多线程编程学习笔记——使用并发集合(二) 四、 使用ConcurrentBag创建一个可扩展的爬虫 本示例在多个独立的即可生产任务又可消费任... 查看详情
线程池应该设置多少核心线程数——java多线程系列学习笔记
前言本章主要讨论线程池合适的线程数量是多少,以及CPU核心数和线程数的关系。我们调整线程池中的线程数量的最主要的目的是为了充分并合理地使用CPU和内存等资源,从而最大限度地提高程序的性能。在实际工作中... 查看详情
多线程编程学习笔记——async和await
接上文多线程编程学习笔记——async和await(一)接上文多线程编程学习笔记——async和await(二)五、 处理异步操作中的异常 本示例学习如何在异步函数中处理异常,学习如何对多个并... 查看详情
多线程编程学习笔记——async和await
接上文多线程编程学习笔记——async和await(一)三、 对连续的异步任务使用await操作符 本示例学习如何阅读有多个await方法方法时,程序的实际流程是怎么样的,理解await的异步调用。1... 查看详情
并发编程系列之如何正确使用线程池?(代码片段)
并发编程系列博客并发编程系列之如何正确使用线程池?在上一章节的学习中,我们掌握了线程的基本知识,接着本博客会继续学习多线程中的线程池知识1、线程是不是越多越好?在学习多线程之前,读者可... 查看详情
并发编程系列之如何正确使用线程池?
并发编程系列博客并发编程系列之如何正确使用线程池?在上一章节的学习中,我们掌握了线程的基本知识,接着本博客会继续学习多线程中的线程池知识1、线程是不是越多越好?在学习多线程之前,读者可能会有疑问?如果... 查看详情
多线程多进程和线程池编程
一.python中的GIL二.python多线程编程三.线程间通信-Queue四.线程同步(Lock、RLock、Semaphores、Condition)五.concurrent线程池编码六.多进程编程-multiprocessing七.进程间通信 查看详情
java多线程学习
写在前面的话:此文只能说是java多线程的一个入门,其实Java里头线程完全可以写一本书了,但是如果最基本的你都学掌握好,又怎么能更上一个台阶呢?如果你觉得此文很简单,那推荐你看看Java并发包的的线程池(Java并... 查看详情
scala学习笔记-actor(19)
Scala的Actor类似于Java中的多线程编程。但是不同的是,Scala的Actor提供的模型与多线程有所不同。Scala的Actor尽可能地避免锁和共享状态,从而避免多线程并发时出现资源争用的情况,进而提升多线程编程的性能。此外,ScalaActor的... 查看详情
多线程编程—线程池的实现
多线程编程—线程池的实现 执行与任务分离的组件—线程池 多线程技术主要解决了处理器单元内多个线程执行的问题,它可以显著的减少处理器单元的闲置时间,增加处理器单元的吞吐能力。线程池是多线程编程的一个... 查看详情