5天不再惧怕多线程——第五天 线程池

说到多线程,不可不说线程池,C#中关于池的概念很多,今天来整理下ThreadPool的使用。

是的,如果你很懒,如果你的执行任务比较短,如果你不想对线程做更精细的控制,那么把这些繁琐的东西丢给线程池吧。

一:ThreadPool

好了,下面看看TheadPool下有哪些常用的方法。

1:GetMaxThreads,GetMinThreads

首先我们肯定好奇线程池到底给我们如何控制线程数,下面就具体的看一看。

class Program
 {
 static void Main(string[] args)
 {
 int workerThreads;

 int completePortsThreads;

 ThreadPool.GetMaxThreads(out workerThreads, out completePortsThreads);

 Console.WriteLine("线程池中最大的线程数{0},线程池中异步IO线程的最大数目{1}", workerThreads, completePortsThreads);

 ThreadPool.GetMinThreads(out workerThreads, out completePortsThreads);

 Console.WriteLine("线程池中最小的线程数{0},线程池中异步IO线程的最小数目{1}", workerThreads, completePortsThreads);
 }
 }


有的同学可能就要问,我可以将1023设置为10230吗?那么就会有10230个线程帮我做事多好啊,其实不然。

①:我先前的文章也说过,线程很多的话,线程调度就越频繁,可能就会出现某个任务执行的时间比线程调度花费的时间短很多的尴尬局面。

②:我们要知道一个线程默认占用1M的堆栈空间,如果10230个线程将会占用差不多10G的内存空间,我想普通的电脑立马罢工。

2:SetMaxTheads,SetMinThreads

当然,默认的线程设置只是一个参考,如果我们处于性能和实际情况确实需要修改也没关系,framework也给我们提供了现成的方法。

class Program
 {
 static void Main(string[] args)
 {
 int workerThreads;

 int completePortsThreads;

 ThreadPool.SetMaxThreads(100, 50);

 ThreadPool.SetMinThreads(20, 10);

 ThreadPool.GetMaxThreads(out workerThreads, out completePortsThreads);

 Console.WriteLine("线程池中最大的线程数{0},线程池中异步IO线程的最大数目{1}\n", workerThreads, completePortsThreads);

 ThreadPool.GetMinThreads(out workerThreads, out completePortsThreads);

 Console.WriteLine("线程池中最小的线程数{0},线程池中异步IO线程的最小数目{1}\n", workerThreads, completePortsThreads);
 }
 }


3: QueueUserWorkItem

需要容纳任务并执行的方法来了,该方法有一个WaitCallBack的委托,我们只需要把将要执行的任务丢给委托,CLR将会在线程池中调派空闲的

线程执行。

namespace ConsoleApplication3
{
 class Program
 {
 static void Main(string[] args)
 {
 ThreadPool.QueueUserWorkItem(Run1);

 Console.Read();
 }

 static void Run1(object obj)
 {
 Console.WriteLine("我是线程{0},我是线程池中的线程吗? \n回答:{1}", Thread.CurrentThread.ManagedThreadId,
 Thread.CurrentThread.IsThreadPoolThread);
 }
 }
}


可能我们也需要像普通的Thread一样带一些参数到工作线程中,QueueUserWorkItem的第二个重载版本解决了我们的问题。

class Program
 {
 static void Main(string[] args)
 {
 ThreadPool.QueueUserWorkItem(Run1, "我是主线程");

 Console.Read();
 }

 static void Run1(object obj)
 {
 Console.WriteLine(obj);
 }
 }

4:RegisterWaitForSingleObject

我们知道,如果我们把要执行的任务丢给线程池后,相当于把自己的命运寄托在别人的手上。

①:我们再也不能控制线程的优先级了。

②:丢给线程池后,我们再也不能将要执行的任务取消了。

是的,给别人就要遵守别人的游戏规则,不过RegisterWaitForSingleObject提供了一些简单的线程间交互,因为该方法的第一个参数是

WaitHandle,在VS对象浏览器中,我们发现EventWaitHandle继承了WaitHandle,而ManualResetEvent和AutoResetEvent都继承于

EventWaitHandle,也就是说我们可以在RegisterWaitForSingleObject溶于信号量的概念。

class Program
 {
 static void Main(string[] args)
 {
 AutoResetEvent ar = new AutoResetEvent(false);

 ThreadPool.RegisterWaitForSingleObject(ar, Run1, null, Timeout.Infinite, false);

 Console.WriteLine("时间:{0} 工作线程请注意,您需要等待5s才能执行。\n", DateTime.Now);

 //5s
 Thread.Sleep(5000);

 ar.Set();

 Console.WriteLine("时间:{0} 工作线程已执行。\n", DateTime.Now);

 Console.Read();
 }

 static void Run1(object obj, bool sign)
 {
 Console.WriteLine("当前时间:{0} 我是线程{1}\n", DateTime.Now, Thread.CurrentThread.ManagedThreadId);
 }
 }


我们知道在Threading下面有一个Timer计时器,当定期触发任务的时候都是由线程池提供并给予执行,那么这里我们溶于信号量的概念以后同样

可以实现计时器的功能。

class Program
 {
 static void Main(string[] args)
 {
 AutoResetEvent ar = new AutoResetEvent(false);

 //参数2000:其实就是WaitOne(2000),采取超时机制
 ThreadPool.RegisterWaitForSingleObject(ar, Run1, null, 2000, false);

 Console.Read();
 }

 static void Run1(object obj, bool sign)
 {
 Console.WriteLine("当前时间:{0} 我是线程{1}\n", DateTime.Now, Thread.CurrentThread.ManagedThreadId);
 }
 }
}


有时候,跑着跑着我们需要在某个时刻停止它,没关系,RegisterWaitForSingleObject返回一个RegisteredWaitHandle类,那么我们就通过

RegisteredWaitHandle来动态的控制,比如说停止计数器的运行。

class Program
 {
 static void Main(string[] args)
 {
 RegisteredWaitHandle handle = null;

 AutoResetEvent ar = new AutoResetEvent(false);

 handle = ThreadPool.RegisterWaitForSingleObject(ar, Run1, null, 2000, false);

 //10s后停止
 Thread.Sleep(10000);

 handle.Unregister(ar);

 Console.WriteLine("小子,主线程要干掉你了。");

 Console.Read();
 }

 static void Run1(object obj, bool sign)
 {
 Console.WriteLine("当前时间:{0} 我是线程{1}", DateTime.Now, Thread.CurrentThread.ManagedThreadId);
 }
 }

时间: 2024-08-01 20:34:23

5天不再惧怕多线程——第五天 线程池的相关文章

浅谈.NET下的多线程和并行计算(五)线程池基础 上

池(Pool)是一个很常见的提高性能的方式.比如线程池连接池等,之所以有这些池是因为线程和数 据库连接的创建和关闭是一种比较昂贵的行为.对于这种昂贵的资源我们往往会考虑在一个池容器中放置 一些资源,在用的时候去拿,在不够的时候添点,在用完就归还,这样就可以避免不断的创建资源和销毁 资源. 如果您做过相关实验的话可能会觉得不以为然,似乎开1000个线程也用不了几百毫秒.我们要这么想 ,对于一个高并发的环境来说,每一秒假设有100个请求,每个请求需要使用(开和关)10个线程,也就 是一秒需要处理10

艾伟:C#多线程学习(四) 多线程的自动管理(线程池)

本系列文章导航 C#多线程学习(一) 多线程的相关概念 C#多线程学习(二) 如何操纵一个线程 C#多线程学习(三) 生产者和消费者 C#多线程学习(四) 多线程的自动管理(线程池) C#多线程学习(五) 多线程的自动管理(定时器) C#多线程学习(六) 互斥对象 在多线程的程序中,经常会出现两种情况: 一种情况: 应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应 这一般使用ThreadPool(线程池)来解决: 另一种情况:线程平时都处于休眠状态,只是周期性地被

多线程-使用多个线程池还是一个线程池

问题描述 使用多个线程池还是一个线程池 最近在技术理论上遇到一个问题,不知道怎么解决. 问题描述:我们交易平台有4个商品(A.B.C.D)需要进行现在交易,交易的核心方法dealorder是 一个加了锁和事务的方法,而且该类是针对每一个商品的,即最多同时可以执行4个dealOrder方法,即每个商品执行一个该方法. @Transactional public synchronized Message dealOrder() CPU核心数是固定的,假如为6核心,目前就存在一个问题, 情况1:假如说

C#多线程学习(四)多线程的自动管理(线程池)

在多线程的程序中,经常会出现两种情况: 一种情况: 应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应 这一般使用ThreadPool(线程池)来解决: 另一种情况:线程平时都处于休眠状态,只是周期性地被唤醒 这一般使用Timer(定时器)来解决: ThreadPool类提供一个由系统维护的线程池(可以看作一个线程的容器),该容器需要 Windows 2000 以上系统支持,因为其中某些方法调用了只有高版本的Windows才有的API函数. 将线程安放在线程池里,需

.NET 中的多线程的概念与线程池

为什么使用多线程 1.使用户界面能够随时相应用户输入 当某个应用程序在进行大量运算时候,为了保证应用程序能够随时相应客户的输入,这个时候我们往往需要让大量运算和相应用户输入这两个行为在不同的线程中进行. 2.效率原因 应用程序经常需要等待一些资源,如等待网络资源,等待io资源,等待用户输入等等.这种情况下使用多线程可以避免CPU长时间处于闲置状态. 用户态,内核态 线程内的资源有两种运行态,即用户态和内核态.某些运算可以在堆栈上进行,这种情况线程是在用户态运行的,某些需要高权限运行的指令,或者某

5天不再惧怕多线程——第一天 尝试Thread

     原本准备在mongodb之后写一个lucene.net系列,不过这几天用到多线程时才发现自己对多线程的了解少之又少,仅仅停留在lock上面, 故这几天看了下线程参考手册结合自己的心得整理一下放在博客上作为自己的学习笔记.      好了,我们知道"负载"是一个很时尚,很牛X的玩意,往大处说,网站需要负载,数据库需要负载.往小处说,线程也需要负载,面对海量的 用户请求,我们的单线程肯定扛不住,那么怎么办,一定要负载,所以说多线程是我们码农必须要熟练掌握的一门技术.     在f

5天不再惧怕多线程——第二天 锁机制

     当多个线程在并发的时候,难免会碰到相互冲突的事情,比如最经典的ATM机的问题,并发不可怕,可怕的是我们没有能力控制. 线程以我的理解可以分为三种 ① 锁. ② 互斥. ③ 信号.   好,这一篇主要整理"锁",C#提供了2种手工控制的锁 一:  Monitor类      这个算是实现锁机制的纯正类,在锁定的临界区中只允许让一个线程访问,其他线程排队等待.主要整理为2组方法.   1:Monitor.Enter和Monitor.Exit          微软很照护我们,给了

5天不再惧怕多线程——第三天 互斥体

     没想到我的前两篇文章还挺受欢迎的,谢谢大家,今天整理下Mutex的使用. 一:Mutex 首先看下MSDN对它的解释:      不错,出现了一个亮点,可用于"进程间同步",既然进程间都可以同步,那线程同步对它来说不是小菜一碟吗?好的,还是看下Mutex在 线程中发挥的神奇功效. 1: 线程间同步     Metux中提供了WatiOne和ReleaseMutex来确保只有一个线程来访问共享资源,是不是跟Monitor很类似,下面我还是举个简单的例子, 注意我并没有给Metu

5天不再惧怕多线程——第四天 信号量

    今天整理"信号量"的相关知识,其实想想也蛮有趣的,锁,互斥,信号量都可以实现线程同步,在framework里面主要有三种. <1>:ManualResetEvent <2>:AutoResetEvent <3>: Semaphore   好,下面就具体看看这些玩意的使用.   一:ManualResetEvent       该对象有两种信号量状态True和False,好奇的我们肯定想知道True和False有什么区别,稍后的例子见分晓,有三