首页 > Python基础教程 >
-
C#教程之.net 多线程的使用(Thread)(2)
执行上面的代码可以得带结果如下:
可创建最大线程数: 2047; 最大 I/O 线程: 1000
最小线程数: 4; 最小 I/O 线程: 4
可以使用的工作线程: 2047; 可用 I/O 线程: 1000
3.设置线程池初始化大小
我们为什么要设置线程池的大小呢?其实我们计算机并不是只运行你一个软件,你的给其他软件预留线程池,一般我们开发的时候使用的线程数是使用 8条、16条、32条和64条。不建议大于64条,毕竟老式的计算机支持有限,如果你计算机线程有2000多,你完全可以分配256以下的线程数。下面我们来看下如何设置。
#region 设置初始化线程 ThreadPool.SetMaxThreads(8, 8);//最小也是CPU核数 ThreadPool.SetMinThreads(4, 4); #endregion #region 获取线程池当前设置 ,默认设置取决于操作系统和CPU int workerThreads = 0; int ioThreads = 0; ThreadPool.GetMaxThreads(out workerThreads, out ioThreads); Console.WriteLine(String.Format("可创建最大线程数: {0}; 最大 I/O 线程: {1}", workerThreads, ioThreads)); ThreadPool.GetMinThreads(out workerThreads, out ioThreads); Console.WriteLine(String.Format("最小线程数: {0}; 最小 I/O 线程: {1}", workerThreads, ioThreads)); ThreadPool.GetAvailableThreads(out workerThreads, out ioThreads); Console.WriteLine(String.Format("可以使用的工作线程: {0}; 可用 I/O 线程: {1}", workerThreads, ioThreads)); #endregion
执行结果如下:
可创建最大线程数: 8; 最大 I/O 线程: 8
最小线程数: 4; 最小 I/O 线程: 4
可以使用的工作线程: 8; 可用 I/O 线程: 8
4.线程池的使用
线程池可以理解为,我们预先创建好指定数量的线程,给程序使用,当前正在使用的子线程一旦使用完成以后,要立即归还,下一个任务使用的时候,我在分配给这个任务。我们使用ManualResetEvent类来控制线程的使用与归还。具体看代码。
#region 多线程的使用 Console.WriteLine("当前主线程id:{0}", Thread.CurrentThread.ManagedThreadId); //首先创建5个任务线程 ManualResetEvent[] mre = new ManualResetEvent[] { new ManualResetEvent(false), new ManualResetEvent(false), new ManualResetEvent(false), new ManualResetEvent(false), new ManualResetEvent(false) }; for (int i = 0; i < 5; i++) { ///false 默认是关闭的,TRUE 默认为打开的 Thread.Sleep(300); ThreadPool.QueueUserWorkItem(t => { //lambda任务 Console.WriteLine("参数的内容是"+t); Console.WriteLine("获取参数值((dynamic)t).num:" + ((dynamic)t).num); int num = ((dynamic)t).num; for (int j = 0; j < num; j++) { Thread.Sleep(2);//一件很耗时的事情 } Console.WriteLine("当前子线程id:{0} 的状态:{1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ThreadState); //这里是释放共享锁,让其他线程进入 mre[i].Set();//可以理解为打开一个线程 //这里是打开共享锁,让其他线程进入 // mre[i].Reset();//可以理解为关闭一个线程 Console.WriteLine(); }, new { num = (i + 1) * 10 }); mre[i].WaitOne(3000); //单独阻塞线程,因为我们使用的是池,索引这里不使用这个,用法同委托异步 } //注意这里,设定WaitAll是为了阻塞调用线程(主线程),让其余线程先执行完毕, //其中每个任务完成后调用其set()方法(收到信号),当所有 //的任务都收到信号后,执行完毕,将控制权再次交回调用线程(这里的主线程) // ManualResetEvent.WaitAll(mre);不建议这么使用 Console.ReadKey(); #endregion
执行结果:
当前主线程id:1
参数的内容是{ num = 10 }
获取参数值((dynamic)t).num:10
当前子线程id:3 的状态:Background
参数的内容是{ num = 20 }
获取参数值((dynamic)t).num:20
当前子线程id:3 的状态:Background
参数的内容是{ num = 30 }
获取参数值((dynamic)t).num:30
当前子线程id:4 的状态:Background
参数的内容是{ num = 40 }
获取参数值((dynamic)t).num:40
当前子线程id:3 的状态:Background
参数的内容是{ num = 50 }
获取参数值((dynamic)t).num:50
当前子线程id:3 的状态:Background
通过执行结果可以看出,第一次任务执行完成以后,把线程归还了,第二次任务分配的还是当前线程,但是第三次任务执行不过来了,我们从小分配了 一次线程。请根据结果分析。关于回调,线程等待使用方法同异步,救赎前一篇有介绍。
总结
1.本文主要演示了多线程和线程池的使用。夸线程访问(主要用于做进度条)。
2.本文介绍了使用多线程的利与弊及线程池的利与弊。
3.Demo 下载地址