线程池 谁践踏了优雅 2022-08-27 03:53 9阅读 0赞 # 一、线程池 # 每次创建一个线程,都会花费几百微秒级别的时间来创建一个私有的局部栈,每个线程默认使用1M的内存。这个可以在使用Thread类的构造函数时设置: new Thread(new ThreadStart(Go), 2); new Thread(new ParameterizedThreadStart(Go("hello")), 3); 提供的两种构造函数方式都提供了对应的设置线程局部栈的大小。线程池通过共享和回收线程的方式来分配这些内存,这样可以使多线程运行在一个非常细粒度级别上而不影响性能。这对于充分利用多核处理器,使用分而治之的方式进行密集型计算的程序中很有用。同时线程池维护一个所有同时运行的工作线程总数的上限,如果有过多的活动线程就会加重操作系统的负担,使诸如CPU缓存失效等问题,当达到这个上限后,就要进行排队。这个线程队列使得任意并发的应用成为可能,如Web服务器就是这种原理。 有多种方式进入线程池: * 通过Task Parallel Library(.NET 4 TPL) * 通过调用ThreadPool.QueueUserWorkItem * 通过异步委托方式 * 使用BackgroundWorker 下面的应用间接地使用了线程池: * WCF、Remoting、ASP.NET、ASMX webservice * System.Timers.Timer和System.Threading.Timer * .NET中以Async结束命名的方法 * PLINQ 注意事项: * 不能对放入线程池中的线程命名,这会使得调试更加困难 * 线程池中的线程总是后台线程 * 阻塞线程池中的线程困难引发额外的延迟 可以使用下面的方式查询当前线程是否在线程池中: CurrentTread.IsThreadPoolThread # 二、进入线程池 # 1、使用TPL进入 使用TPL中的Task类就可以很简单的进入,使用Task.Factory.StartNew方法,传递一个目标函数的委托即可: static void Main(string[] args) { Task.Factory.StartNew(Go); Console.WriteLine("Is Thread Pool: " + Thread.CurrentThread.IsThreadPoolThread.ToString()); Console.ReadKey(); } static void Go() { Console.Write("Is Thread Pool: " + Thread.CurrentThread.IsThreadPoolThread.ToString()); } ![SouthEast][] Task.Factory.StartNew返回一个Task对象可以用来监控这个任务。 同时可以使用泛型类Task<TResult>,如下: static void Main(string[] args) { Task<string> task = Task.Factory.StartNew<string>(Go); Console.WriteLine("Is Thread Pool: " + Thread.CurrentThread.IsThreadPoolThread.ToString()); if (task.IsCompleted) { string result = task.Result; Console.WriteLine(task.IsCompleted.ToString() + result); } Console.ReadKey(); } static string Go() { return Thread.CurrentThread.IsThreadPoolThread.ToString(); } ![SouthEast 1][] 如果在工作线程中出现异常,当获取Task的Result属性时会重新引发AggregateException异常,如果没有查询Result或者没有调用Wait方法,所有未处理的异常都会终止进程执行。 2、不使用TPL 对于.NET 4.0以前的版本是无法使用TPL的,必须使用ThreadPool.QueueUserWorkItem(类似Task类功能)和异步委托(类似Task<TResult>),但是这两个没有前面所述方法快、也没有那么方便和很好的扩展性。两种方式的使用如下: static void Main() { ThreadPool.QueueUserWorkItem (Go); ThreadPool.QueueUserWorkItem (Go, 123); Console.ReadLine(); } static void Go (object data) // data will be null with the first call. { Console.WriteLine ("Hello from the thread pool! " + data); } static void Main() { Func<string, int> method = Work; method.BeginInvoke ("test", Done, method); // ... // } static int Work (string s) { return s.Length; } static void Done (IAsyncResult cookie) { var target = (Func<string, int>) cookie.AsyncState; int result = target.EndInvoke (cookie); Console.WriteLine ("String length is: " + result); } # 三、线程池的优化 # 线程池拥有的最大线程数可以通过ThreadPool.SetMaxThreads设置,默认值如下: * 32位的.NET4.0环境为1023个 * 64位的.NET4.0环境为32768个 * .NET 3.5为每个CPU核 250个 * .NET2.0 为每个CPU核25个 线程池管理器在分配任务时通过添加新的线程来应对额外的工作量,当达到极限后开始排队。在非活动的闲置期,管理器可以删除一些可疑的线程从而可以得到更好的吞吐量。当然也可以使用Thread.SetMinThreads来设置最小的线程数目:最小线程数是优化线程池的高级方式,这个将指导管理器对于线程的分配没有延迟。提高最小数目可以当在有阻塞线程时提高并发量。 提高线程的最小数目并不能保证至少有相应个线程在线程池中,线程只会在有需要的时候创建。同时这个会指导池管理器创建到最小数目的线程。线程池在分配线程时会有半秒的延迟,之所以要有这个延迟就是为了防止突然的大量线程分配导致应用程序内存占用过大。线程池对于队列保持等待超过半秒时就会通过创建新的线程来响应请求,没半秒创建一个只到达到最大线程数。 这个半秒的延迟是有利也有弊的,弊端在于当一个阻塞的线程出现时并不需要延迟半秒,例如一个查询数据库或者下载网页的线程。这时需要告诉池管理器不要延迟进程线程分配,因此就需要用到SetMinThreads来设置: ThreadPool.SetMinThreads(50,50); [SouthEast]: /images/20220824/8c74d06e708b45c99987617df2256fbb.png [SouthEast 1]: /images/20220824/9c5237c46d0445e1ba1b6e14ddddf457.png
相关 Java 线程池、Runnable线程池、Callable线程池 线程池: 其实就是一个容纳多个线程的容器,其中的线程可以反复的使用,省去了频繁创建和销毁过程对象的操作,无需反复创建线程面消耗过多资源。 为什么要用线程池: 合理 青旅半醒/ 2023年02月26日 12:30/ 0 赞/ 111 阅读
相关 线程、线程池 创建线程的3种方法: package com.frank.threadPool.createThread; / @author 小石潭记 布满荆棘的人生/ 2022年10月22日 04:27/ 0 赞/ 434 阅读
相关 线程池 1.所谓线程池,就是程序的初始化阶段,就预先创建一批线程,每个线程都做好准备干活; 2.然后有一个任务列表,一开始为空,当有任务来了,就往任务列表里面添加;这个任务列表 痛定思痛。/ 2022年06月13日 13:22/ 0 赞/ 362 阅读
相关 线程池 西施越溪女,明艳光云海 最近用线程池和不用线程池做了个速度的测试,在这里备注下: 结果是速度不相上下; public static void main(Str 妖狐艹你老母/ 2022年05月20日 02:35/ 0 赞/ 323 阅读
相关 线程池 线程池 Java里面线程池的顶级接口是 java.util.concurrent.Executor , 但是严格意义上讲 Executor并不是一个线程池,而只是一个 迈不过友情╰/ 2022年03月06日 14:34/ 0 赞/ 442 阅读
相关 线程池 线程池 > 从字面义上来讲,是指管理一组同构工作线程的资源池。线程池是与工作队列密切相关的,其中在工作队列中(Worker Queue)保存了所有等待执行的任务。工作者( 清疚/ 2021年12月11日 03:35/ 0 赞/ 425 阅读
相关 线程池 可preStart一个或全部core thread 0,小于core则来一个任务建一个线程(firstTask),队列,额外线程,拒绝 一个AtomicInteger的 今天药忘吃喽~/ 2021年11月23日 03:40/ 0 赞/ 450 阅读
相关 线程池 1、先创建线程池 import java.util.concurrent.ArrayBlockingQueue; import java.util.concu 拼搏现实的明天。/ 2021年11月09日 14:28/ 0 赞/ 459 阅读
还没有评论,来说两句吧...