C# 多线程学习系列一
一、Windows线程的由来 关于操作系统的一些知识
(1)、单个"工作线程"的问题
早期的Windows没有线程的概念,整个系统只有一个"工作线程",上面同时跑着操作系统代码和应用程序代码.这种方式最大的缺点就是,一个应用程序运行时会霸占整台机器(应为只有一个工作线程),且当它发生死循环时,会造成PC停止工作.如果此时重启,更shit的是,所有的应用程序都会停止,且丢失数据.
(2)、Windows进程
i、什么是Windows进程,以及它解决的问题
MS为了解决单个"工作线程"的问题,设计了新的内核,该内核实现了Windows进程的功能,每个Windows进程(应用程序要使用的资源集合)运行一个应用程序,如下图:
一个Chrome浏览器进程包含了很多子进程(子进程可以共享父进程的资源),后面包含了正在使用的资源集合,包括CPU、内存等.每个进程都有一个虚拟空间地址(PID).
当一个应用程序应为代码故障发生卡死等问题,并不会影响其他的应用程序的运行,只需要打开任务管理器,将该进程关闭即可.其他应用程序的数据也不会丢失,因为它们是彼此独立的进程.
ii、Window进程的安全性
在Windows中,进程之间不能相互访问(不包括父子进程),单个进程也无法访问Windows内核.
iii、关于CPU的问题
虽然Windows进程很好的解决了单个"工作线程"的问题,Windows不会发生一个应用程序崩溃,所有应用程序全都停止且所有运行着的应用程序的数据丢失的情况。但是如果PC只有一个CPU,当CPU本身发生死循环等问题,还是会导致PC停止工作.
iv、什么是Windows线程,以及Windows线程解决的问题
MS为了解决单个进程执行异常,导致CPU停止工作的问题,设计了Windows线程,它的作用是对CPU进行虚拟化,Windows会给每个Windows进程分配一个Windows线程,该线程相当于一个虚拟的CPU(包含CPU所有的功能),如果应用程序的代码进入死循环,相关进程会被停止,但是其他的应用程序进程并不会停止,会继续执行.因为它们拥有自己的线程(虚拟CPU).
2、Windows线程的消耗
虽然Windows线程保证了Windows的可靠性和健壮性,但是天下没有免费的午餐,随之带来的肯定是其他的PC资源消耗.这里不想介绍太多操作系统级别的东西,只说一些直观的我们能看到的.就以我的笔记本为例,打开任务管理器如下:
我的笔记本此时跑着176个进程,所以理论上至少有176个线程,但是实际却有2103个线程,平均每个进程12个线程.下面是我笔记本的配置
双核,理论上最优的配置是,只有两个线程,应为涉及到线程上下文切换(从一个线程上下文切换到另一个上下文),而上下文的切换的性能代价是十分大的.
我的CPU利用率为7%,说明93%的时间,这2103个线程啥事都没干,严重的浪费了我的内存.如果这个时候开启了远程桌面服务,假设10个用户连了我的笔记本,所有的开销会翻倍.
当然虽然线程的开销很大,但是相比于创建进程,开销相比较小.但是开发应用程序的时候,还是要合理的使用线程!
二、为什么要使用多线程
主要有两点,拿Windows来举例
(1)、Windows使用线程,每个线程拥有一个虚拟的CPU,包含CPU所有的功能,当一个应用程序使用的线程因为代码问题,发生故障时,Windows会关闭这个线程,但是这个线程使用的是虚拟的CPU,所以不会影响其他应用程序使用它们的线程,也就是虚拟CPU.所以线程保证了CPU的高可用.同时现在的电脑往往都有多个CPU,利用这个特性,我们可以使用代码创建多个线程,去执行不同的任务,比如一个Windows桌面程序,可以让主线程去处理用的输入,创建其他的线程去处理桌面程序的UI界面.这样用户体验就会非常好.不会说必须等到桌面UI全部初始化完,用户才能执行输入操作.
(2)、Windows每个CPU就能调度一个线程,如果你的PC有个多CPU,那么它们就能协同操作,同时也就是并发的执行多个任务.但是虽然线程能并发执行很多任务,但是如果创建的线程过多,理论上一个CPU只能调度一个线程,但是你创建的线程如果比CPU还多,那么windows就会进行上下文切换,这个性能损失是很可观的(不考虑创建线程本身的开销),所以关于线程创建的数量,还是需要慎重考虑.
三、关于CPU利用率
CPU利用率简单点说,就是CPU的使用效率,如果当PC长时间的响应I/O,或者在驱动硬件设备干活,而CPU本身却很空闲,这种情况CPU利用率就很低.
四、线程调度和优先级
1、线程调度
首先Windows是一个抢占式的操作系统,抢占式操作系统说白点就是线程的切换,因为大多数Windows操作系统运行了不止一个应用程序,而这些应用程序运行了不止一个线程,最后这些所有的线程加起来肯定超过PC的CPU核数(上面说了一个CPU只能调度一个线程),那么为了保证这些线程能尽可能的同时运行,所以Windows操作系统必须进行频繁的上下文切换,保证这些线程能同时调度.这也就是为什么你在Windows的操作系统同时开启多个应用程序会非常卡的原因.因为一下次有N多个线程同时开启,导致CPU工作压力飙升.
那么为什么说是抢占式的呢?因为每个内核包含一个上下文对象,这个对象包含了线程上次执行完毕的CPU寄存器状态,在一个CPU的时间片执行完毕之后(也就是一个线程执行完毕之后),Windows会便利所有的上下文,找出一个适合调度的上下文,并切换到这个上下文,执行该线程.这就是所谓的抢占式.Windows可以在任何时间抢占当前正在执行上下文,切换到下一个上下文,只要Windows觉得当前上下文更值得被调度。注:这是个很复杂的过程.所以你无法确保创建的线程会在什么时候被调度,以及调度多长时间.这些都由Windows来判断.说白点,它比你更聪明.并且他考虑的比你更全面.哈哈!
2、优先级
虽然你无法确定你的线程什么时候被调度,但是当你有一个线程这个线程执行非常重要的任务,但是Window内核本身并不能保证它的执行优先级,所以我们必须使用其他的手段来确保它能优先于其他线程的执行.万幸的是,Window也考虑到了这一点,设计了优先级这一概念,来满足我们的业务需求.
(1)、进程优先级
Windows支持6个进程优先级类,如下:
Idle(空闲),一般执行在操作系统空闲的时候执行的程序,比如Windows自动更新服务.屏幕保护程序等.
Below Normal(低于普通优先级)
Normal(普通优先级)
Above Normal(高于普通)
Hign(高)如果又非常关键的进程,可以使用.
Realtime(实时,超高优先级)不建议使用,会影响操作系统的进程,会造成"死机"的情况,使用这个优先级有权限要求(管理员有这个权限)
(2)、线程优先级
Windows为线程定义了0~31的优先级,Windows会优先调度高优先级的线程,注意,会存在线程抢占的情况,如果开启了一个应用程序,当该程序里面有一个31优先级的线程,那么Windows会挂起当前正在执行的低优先级的线程,给该线程使用.单核机器,如果存在过多的较高优先级的线程,那么低线程将不会被调度,这是种很shit的情况,所以要谨慎使用.
Windows提供了7个线程优先级
Idle(空闲)操作系统空闲时执行的线程
Lowest(最低级别)
Below Normal(低于正常)
Normal
Above Normal
Hignest
Time-Critical(实时)
(3)、关于进程优先级和线程优先级的联系
真实的线程优先级的大小取决于进程优先级,如果两个进程优先级一样,那么只看线程优先级大小.具体请看CLR via C#提供的这张表
C# 多线程学习系列一的更多相关文章
- .NET并行与多线程学习系列一
并行与多线程学习系列一 一.并行初试: public static void test() { ; i < ; i++) { Console.WriteLine(i); } } public s ...
- 多线程学习系列二(使用System.Threading)
一.什么是System.Threading.Thread?如何使用System.Threading.Thread进行异步操作 System.Threading.Thread:操作系统实现线程并提供各种 ...
- C# 多线程学习系列三之CLR线程池系列之ThreadPool
一.CLR线程池 1.进程和CLR的关系一个进程可以只包含一个CLR,也可以包含多个CLR2.CLR和AppDomain的关系一个CLR可以包含多个AppDomain3.CLR和线程池的关系一个CLR ...
- C# 多线程学习系列二
一.关于前台线程和后台线程 1.简介 CLR中线程分为两种类型,一种是前台线程.另一种是后台线程. 前台线程:应用程序的主线程.Thread构造的线程都默认为前台线程 后台线程:线程池线程都为后台线程 ...
- C# 多线程学习系列四之ThreadPool取消、超时子线程操作以及ManualResetEvent和AutoResetEvent信号量的使用
1.简介 虽然ThreadPool.Thread能开启子线程将一些任务交给子线程去承担,但是很多时候,因为某种原因,比如子线程发生异常.或者子线程的业务逻辑不符合我们的预期,那么这个时候我们必须关闭它 ...
- C#多线程学习(一) 多线程的相关概念(转)
什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程所组成的. 什么是线程?线程是程序中的一个执行流,每个线程都有自己的专有寄 ...
- C#多线程学习(一) 多线程的相关概念
什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程所组成的. 什么是线程?线程是程序中的一个执行流,每个线程都有自己的专有寄 ...
- [转载]C#多线程学习(一) 多线程的相关概念
原文地址:http://www.cnblogs.com/xugang/archive/2008/04/06/1138856.html 什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的 ...
- C#多线程学习(六) 互斥对象
如何控制好多个线程相互之间的联系,不产生冲突和重复,这需要用到互斥对象,即:System.Threading 命名空间中的 Mutex 类. 我们可以把Mutex看作一个出租车,乘客看作线程.乘客首先 ...
随机推荐
- 利用cglib包实现Spring中aop的<aop:advisor>功能
一:前言 还有<aop:before>/<aop:after>/<aop:around>的没有实现,不过根<aop:advisor>是差不多的,就是要额 ...
- cyclone iv中DDR2的本地接口时序
本地接口 信号名 方向 描述 local_burstbegin input 如果local_ready无效不起作用.IP核在local_write_req为高时,在phy_clk上升沿采样.当lo ...
- Android: Custom View和include标签的区别
Custom View, 使用的时候是这样的: <com.example.home.alltest.view.MyCustomView android:id="@+id/customV ...
- java基础-day33
第10天 Transaction事务 今日内容介绍 u 事务管理 u 转账案例 u 事务总结 第1章 事务管理 1.1 事务概述 l 事务指的是逻辑上的一组操作,组成这组操作的各个单元要么全都 ...
- java基础-day16
第05天 API 今日内容介绍 u Object类 & System类 u 日期相关类 u 包装类&正则表达式 第1章 Object类 & System类 1.1 ...
- JavaScript 获取鼠标点击位置坐标
在一些DOM操作中我们经常会跟元素的位置打交道,鼠标交互式一个经常用到的方面,令人失望的是不同的浏览器下会有不同的结果甚至是有的浏览器下没结果,这篇文章就上鼠标点击位置坐标获取做一些简单的总结,没特殊 ...
- ASP.NET Web API 框架研究 Self Host模式下的消息处理管道
Self Host模式下的ASP.NET Web API与WCF非常相似,都可以寄宿在任意类型的托管应用程序中,宿主可以是Windows Form .WPF.控制台应用以及Windows Servic ...
- 编写高质量iOS与OS X代码的52个有效方法
第一章重点: 第一条:OC的起源 OC由smalltalk语言演化而来的语言为消息结构(messaging structure)语言,其运行时所因执行的的代码由运行环境来决定:函数调用(functio ...
- sed,grep,进阶+source+export+环境变量
三剑客之sed 概括流程:从文件或管道中,可迭代读取. 命令格式: sed(软件) 选项 sed命令 输入文件 增 两个sed命令: a: 追加文本到指定行后 i: 插入到指定行前 sed -i '1 ...
- 元组(tuple)基本操作
1.定义元组,Python的元组和列表类似,不同之处在于元组中的元素不能修改(因此元组又称为只读列表),且元组使用小括号而列表使用中括号 dimensions.py , ) print(dimensi ...