1:网摘一段话:不同的托管环境会设置不同的上限。如在.NET 2.0 SP1之后,普通的Windows应用程序(如控制台或WinForm/WPF),会将其设置为“处理器数 * 250”。也就是说,如果您的机器为2个2核CPU,那么CLR线程池的容量默认上限便是1000,也就是说,它最多可以管理1000个线程同时运行——很多情况下这已经是一个很可怕的数字了,如果您觉得这还不够,那么就应该考虑一下您的实现方式是否可以改进了。2:看我的一段代码:
class Program
{
static void Main(string[] args)
{
WaitCallback callBack = new WaitCallback(PooledFunc);
ThreadPool.QueueUserWorkItem(PooledFunc, "张三");
ThreadPool.QueueUserWorkItem(callBack,"李四");
ThreadPool.QueueUserWorkItem(callBack,"王二");
Console.ReadLine();
}
static void PooledFunc(object state)
{
Console.WriteLine("当前线程的标识符是: {0}", Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("{0}开始从服务器下载文件", (string)state);
int ticks = Environment.TickCount;
while (Environment.TickCount - ticks < 2000) ; //CPU一直处于忙碌
Console.WriteLine("{0}下载完了....", (string)state);
}
}上面的代码,线程池中,并没有三条线程同时执行,王二那条线程是在张三线程执行完之后才执行的,并且从ManagedThreadId值可以看出,王二和张三使用的是同一条线程。而上面那段话,不是说的可以有1000条线程同时执行的吗?我的电脑的CPU是2核的怎么才2条线程同时执行呢?
class Program
{
static void Main(string[] args)
{
WaitCallback callBack = new WaitCallback(PooledFunc);
ThreadPool.QueueUserWorkItem(PooledFunc, "张三");
ThreadPool.QueueUserWorkItem(callBack,"李四");
ThreadPool.QueueUserWorkItem(callBack,"王二");
Console.ReadLine();
}
static void PooledFunc(object state)
{
Console.WriteLine("当前线程的标识符是: {0}", Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("{0}开始从服务器下载文件", (string)state);
int ticks = Environment.TickCount;
while (Environment.TickCount - ticks < 2000) ; //CPU一直处于忙碌
Console.WriteLine("{0}下载完了....", (string)state);
}
}上面的代码,线程池中,并没有三条线程同时执行,王二那条线程是在张三线程执行完之后才执行的,并且从ManagedThreadId值可以看出,王二和张三使用的是同一条线程。而上面那段话,不是说的可以有1000条线程同时执行的吗?我的电脑的CPU是2核的怎么才2条线程同时执行呢?
如果你的程序是故意想“烧热CPU来取暖”,那么可以这样写。否则,一个异步的编程不是这样写的。它可能是类似于:var gate1 = new ManualResetEvent(false);
//注册第一个线程,并且将gate1作为参数,线程执行完之前执行gate1的Set方法。
var gate2 = new ManualResetEvent(false);
//注册第一个线程,并且将gate2作为参数,线程执行完之前执行gate2的Set方法。
var gate3 = new ManualResetEvent(false);
//注册第一个线程,并且将gate3作为参数,线程执行完之前执行gate3的Set方法。
WaitHandle.WaitAll(new WaitHandle[] { gate1, gate2, gate3 });
这就会阻塞直到三个线程都执行完才继续。此时不必写一个循环语句去烧CPU。
异步程序的基本思维就是回调式的。例如PooledFunc("张三", myCallBack);这个语句发出,那么一瞬间这个语句就执行完了。因为它只是注册线程而已。使用异步编程,其实应该改变我们的思维习惯。你首先要把你的程序系统按照异步回调的思维方式重新表达,甚至重新研究业务逻辑,才能写好异步程序。主要就是要突出这个“回调处理”的作用,好的异步程序几乎不用同步阻塞。否则,如果你的思维总是函数式思维,你的思维上就是“调用-返回值,然后再调用-返回值”这种同步顺序思维模式,那么很多人会滥用阻塞方法,用线程/异步的语法去模拟同步程序的处理流程,其实写不好异步程序。
线程池分配线程的流程是这样的
1.请求线程池分配线程
2.线程池查询可用线程池队列中的线程。
2.1.如果有可用线程,则使用可用线程,将可用线程从可用线程队列。
2.2.1.如果没有可用线程,并且线程池未达到上限,则新创建1个工作线程,并加入到线程池中。
2.2.2.如果没有可用线程,并且线程池已经达到上限,则等待任意一条线程池中的线程工作完毕,再回到第二步。
3.线程工作完毕后,通知线程池线程工作完毕。线程池将此线程放入到可用线程池。ThreadPool简单理解,就是用 Monitor 和 Thread 2个类的进一步封装。线程池中包含2种不同类型的线程,1种是工作线程,1种是IO线程。他们的工作内容不同,但都占用一个线程。如果你真想开N条线程的话,建议直接使用Thread去创建。
是由两个因素决定的,一是MinThreads,你的是双核 那么默认的MinThreads的个数就是2你可以用ThreadPool.SetMinThreads 来设置MinThreads的个数第二个因素是 while (Environment.TickCount - ticks < 2000) ;因为CPU一直在工作,没办法让最小线程数之外的线程来处理只能等待CPU的某个核心处理完,才会让其他线程来工作,所以只有两条线程运行关于线程ID 是两个,如果你设置成 while (Environment.TickCount - ticks < 5000) ;你会看到线程ID会不一致,但依然只会有两个线程在同时工作因为你的CPU是双核,任意一个线程的工作都是一直让CPU满负载 那么只会有两个线程同时在工作简单的改法就是 while (Environment.TickCount - ticks < 2000) ;
=>
Thread.Sleep(2000);