池(Pool)是一个很常见的提高性能的方式。比如线程池连接池等,之所以有这些池是因为线程和数据库连接的创建和关闭是一种比较昂贵的行为。对于这种昂贵的资源我们往往会考虑在一个池容器中放置一些资源,在用的时候去拿,在不够的时候添点,在用完就归还,这样就可以避免不断的创建资源和销毁资源。

首先,要理解线程池线程分为两类工作线程和IO线程,可以单独设置最小线程数和最大线程数:ThreadPool.SetMinThreads(2, 2);

ThreadPool.SetMaxThreads(4, 4);

最大线程数很好理解,就是线程池最多创建这些线程,如果最大4个线程,现在这4个线程都在运行的话,后续进来的线程只能排队等待了。那么为什么有最小线程一说法呢?其实之所以使用线程池是不希望线程在创建后运行结束后理解回收,这样的话以后要用的时候还需要创建,我们可以让线程池至少保留几个线程,即使没有线程在工作也保留。上述语句我们设置线程池一开始就保持2个工作线程和2个IO线程,最大不超过4个线程。

至于线程池的使用相当简单先来看一段代码:for(inti = 0; i < totalThreads; i++)

{

ThreadPool.QueueUserWorkItem(o =>

{

Thread.Sleep(1000);

inta, b;

ThreadPool.GetAvailableThreads(outa, outb);

Console.WriteLine(string.Format("({0}/{1}) #{2} : {3}", a, b, Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("mm:ss")));

});

}

Console.WriteLine("Main thread finished");

Console.ReadLine();

代码里面用到了一个事先定义的静态字段:static readonly inttotalThreads = 10;

代码运行结果如下:

每一个线程都休眠一秒然后输出当前线程池可用的工作线程和IO线程以及当前线程的托管ID和时间。我们通过这段代码可以发现线程池的几个特性:

1) 线程池中的线程都是后台线程,如果没有在主线程使用ReadLine的话,程序马上会退出。

2) 线程池一开始就占用了2个线程,一秒后占用了4个线程,工作线程将会由3-6四个线程来处理。

3) 线程池最多使用了4个工作线程和0个IO线程。

那么,我们如何知道线程池中的线程都运行结束了呢,可以想到上文用过的Monitor结构:Stopwatchsw = Stopwatch.StartNew();

for(inti = 0; i < totalThreads; i++)

{

ThreadPool.QueueUserWorkItem(o =>

{

Thread.Sleep(1000);

inta, b;

ThreadPool.GetAvailableThreads(outa, outb);

Console.WriteLine(string.Format("({0}/{1}) #{2} : {3}", a, b, Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("mm:ss")));

lock(locker)

{

runningThreads--;

Monitor.Pulse(locker);

}

});

}

lock(locker)

{

while(runningThreads > 0)

Monitor.Wait(locker);

}

Console.WriteLine(sw.ElapsedMilliseconds);

Console.ReadLine();

程序中用到了两个辅助字段:static objectlocker = new object();static intrunningThreads = totalThreads;

程序运行结果如下:

我们看到,10个线程使用了3.5秒全部执行完毕。20个线程呢?

需要6秒。细细分析这2个图我们不难发现,新的线程不是在不够用的时候立即创建而是延迟了0.5秒左右的时间,这是因为线程池会等待一下看是不是有线程在这段时间内可用,如果实在没有的话再创建。其实可以这么理解这6秒,前一秒只有2个线程,后4秒有4个线程执行了16个,最后1秒又只有2个线程了,所以一共是2+4*4+2=20,6秒处理了20个线程。

ThreadPool还有一个很有用的方法可以注册一个信号量,我们发出信号后所有关联的线程才执行,否则就一直等待,还可以指定等待的时间:

首先定义信号量和存储结果的字段:staticManualResetEventmre = newManualResetEvent(false);

static intresult = 0;程序如下:Stopwatchsw = Stopwatch.StartNew();

for(inti = 0; i < totalThreads; i++)

{

ThreadPool.RegisterWaitForSingleObject(mre, (state, istimeout) =>

{

Thread.Sleep(1000);

inta, b;

ThreadPool.GetAvailableThreads(outa, outb);

Interlocked.Increment(refresult);

Console.WriteLine(string.Format("({0}/{1}) #{2} : {3}", a, b, Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("mm:ss")));

lock(locker)

{

runningThreads--;

Monitor.Pulse(locker);

}

}, null, 500, true);

}

Thread.Sleep(1000);

result = 10;

mre.Set();

lock(locker)

{

while(runningThreads > 0)

Monitor.Wait(locker);

}

Console.WriteLine(sw.ElapsedMilliseconds);

Console.WriteLine(result);

Console.ReadLine();

程序结果如下:

注意到RegisterWaitForSingleObject的第一个参数就是信号量,第二个参数就是方法主体(接受两个参数分别是传给线程的一个状态变量以及线程执行的时候是否超时),第三个参数是状态变量,第四个参数超时时间我们设置了500毫秒,由于主线程在1秒后发出信号,超时500毫秒,所以这些线程并没等到信号的发出500毫秒之后就运行了。之所以程序的运行结果为30是因为即使500毫秒之后线程超时开始执行但是也要等1秒才累加结果,在这个时候主线程早已把结果更新为10了,所以累加从10开始而不是0开始。最后布尔参数为true表明接受到信号后只线程执行一次。

观察到,所有线程执行完毕花了7秒的时间,除去开始的等待时间0.5秒,相比之前的例子还多了0.5秒的时间。这是为什么呢?请大家帮忙分析分析。还有一个更奇怪的问题是,RegisterWaitForSingleObject消耗的是IO线程而不是工作线程,难道微软觉得RegisterWaitForSingleObject常见于IO操作的应用还是不希望不浪费工作线程?

linux 多线程并行计算,浅谈.NET下的多线程和并行计算(五)线程池基础上相关推荐

  1. 浅谈多核CPU、多线程与并行计算

    浅谈多核CPU.多线程与并行计算 xiaofei0859 2017-05-09 17:07:11  3646  收藏 展开 0.前言 笔者用过MPI和C#线程池,参加过比赛,有所感受,将近一年来,对多 ...

  2. python中文字符串编码_浅谈python下含中文字符串正则表达式的编码问题

    前言 Python文件默认的编码格式是ascii ,无法识别汉字,因为ascii码中没有中文. 所以py文件中要写中文字符时,一般在开头加 # -*- coding: utf-8 -*- 或者 #co ...

  3. Linux内核之浅谈内存寻址

    Linux内核之浅谈内存寻址 前言 最近在看内存寻址的内容,略有所得,发此文与大家一起交流.我们知道计算机是由硬件和软件组成,硬件主要包括运算器.控制器.存储器.输入设备和输出设备,软件主要是操作系统 ...

  4. js打印线程id_浅谈python中的多线程和多进程(二)

    原创:hxj7 本文继续分享一个关于python多线程和多进程区别的例子 前文<浅谈python中的多线程和多进程>中我们分享过一个例子,就是分别利用python中的多线程和多进程来解决高 ...

  5. 获得进程id_浅谈python中的多线程和多进程(二)

    原创:hxj7 本文继续分享一个关于python多线程和多进程区别的例子 前文<浅谈python中的多线程和多进程>中我们分享过一个例子,就是分别利用python中的多线程和多进程来解决高 ...

  6. python打开文件夹中的tiff_浅谈python下tiff图像的读取和保存方法

    对比测试 scipy.misc和 PIL.Image和 libtiff.TIFF三个库 输入: 1. (读取矩阵) 读入uint8.uint16.float32的lena.tif 2. (生成矩阵) ...

  7. 计算机病毒的隐藏方式有ign,浅谈windows下的病毒隐藏技术.doc

    浅谈windows下的病毒隐藏技术 浙江工业职业技术学院 毕业论文 (2011届) 浅谈windows下的病毒隐藏技术 学生姓名 学 号 分 院 专 业 信 指导教师 完成日期 2011年5月 19日 ...

  8. 浅谈线程池(上):线程池的作用及CLR线程池

    线程池是一个重要的概念.不过我发现,关于这个话题的讨论似乎还缺少了点什么.作为资料的补充,以及今后文章所需要的引用,我在这里再完整而又简单地谈一下有关线程池,还有.NET中各种线程池的基础.更详细的内 ...

  9. linux系统安装coerplayer,浅谈Linux操作系统下的多媒体播放器

    freeamp 2.1.0 freeamp是一个遵循gpl的音频播放器,彻底得free以及支持跨平台(同时支持window和linux)使用是它最大的特点.虽然在支持格式上略显单薄,但整体界面以及操作 ...

最新文章

  1. 《深入理解计算机系统》读书随笔-位操作
  2. 到底什么是几何深度学习?Twitter 首席科学家Bronstein深度解读
  3. 远控免杀专题12--Green-Hat-Suite免杀
  4. 华为云教你7天玩转电商应用性能调优,课程免费速来报名!
  5. 2021年中国成人商店市场趋势报告、技术动态创新及2027年市场预测
  6. 9-13 ruby环境准备
  7. 什么时候需要档案_需要什么
  8. 江西省萍乡市谷歌高清卫星地图下载
  9. android视频 转 gif,手机视频转gif转换器 安卓手机怎样把视频转化成GIF图片,手机视频转GIF方法...
  10. Centos7修改服务器密码
  11. 新年新气象,90行代码菜鸟用Python制作小姐姐新年日历天气卡,送人太有面子啦!...
  12. Android 人民币符号少一横问题解决方案
  13. 微信版“花呗”全面开放,人人都可以申请!
  14. 一文弄懂责任链设计模式
  15. 这个地图绘制工具太赞了,推荐~~
  16. LINUX从零开始——ENGINEER(云计算应用管理)——Day4-1 [配置Linux网络 、源码编译安装、自定义Yum仓库、日志管理]
  17. 未来拟投10亿!保乐力加峨眉山威士忌酒厂正式揭幕;欧舒丹收购美国护理品牌约83%间接股权 | 美通社头条...
  18. can差分线阻抗_差分阻抗
  19. 教学生用计算机画画,六年级美术教材《用计算机画画》
  20. 微信小程序 - 蓝牙BLE小程序开发

热门文章

  1. background背景图片自适应_一侧定宽、一侧自适应,尽量多的方案实现?「前端剑指offer」...
  2. 马吕斯定律matlab拟合,Matlab插值模拟在光的偏振中的应用
  3. unity协程_[C#进阶]C#实现类似Unity的协程
  4. C++之指针探究(十六):typedef结合函数指针
  5. python制作查询工具发给别人使用_用Python制作天气查询软件
  6. java删除多选项_java – 选项菜单默认灰色边框删除
  7. python 列表为空报错_对比几段代码,看看你是 Python 菜鸟还是老鸟
  8. mysql mvcc gap lock_为什么说 MVCC 和 Gap Lock 解决了 MySQL 的幻读问题
  9. ieda中快捷搜索_快捷指令(07)早上好(三)播报当日日程安排。
  10. C++深拷贝与浅拷贝以及写时复制