多线程的代价及上下文切换
Contents
多线程的代价及上下文切换
http://www.cnblogs.com/shangxiaofei/p/5762895.html
关于时间, 创建线程使用是直接向系统申请资源的, 这里调用系统函数进行分配资源的话耗时不好说。 关于资源, Java线程的线程栈所占用的内存是在Java堆外的, 所以是不受java程序控制的, 只受系统资源限制, 默认一个线程的线程栈大小是1M (当让这个可以通过设置-Xss属性设置,但是要注意栈溢出问题), 但是, 如果每个用户请求都新建线程的话, 1024个用户光线程就占用了1个G的内存, 如果系统比较大的话,一下子系统资源就不够用了,最后程序就崩溃了。 对操作系统来说,创建一个线程的代价是十分昂贵的, 需要给它分配内存、列入调度,同时在线程切换的时候还要执行内存换页,CPU 的缓存被 清空,切换回来的时候还要重新从内存中读取信息,破坏了数据的局部性。
http://www.cnblogs.com/ktgu/p/3529144.html
多线程的代价
使用多线程往往可以获得更大的吞吐率和更短的响应时间,但是,使用多线程不一定就比单线程程序跑的快,这取决于我们程序设计者的能力以及应用场景的不同。不要为了多线程而多线程,而应考虑具体的应用场景和开发实力,使用多线程就是希望能够获得更快的处理速度和利用闲置的处理能力,如果没带来任何好处还带来了复杂性和一些定时炸弹,那还傻逼了吗?只有在使用多线程给我们带来的好处远大于我们付出的代价时,才考虑使用多线程,有时候可能引入多线程带来的性能提升抵不过多线程而引入的开销,一个没有经过良好并发设计得程序也可能比使用单线程还更慢。
多线程给我们带来的代价
设计更复杂
多线程程序在访问共享数据的时候往往需要我们很小心的处理,否则就会出现难以发现的BUG,一般地,多线程程序往往比单线程程序设计会更加复杂 (尽管有些单线程处理程序可能比多线程程序要复杂) ,而且错误很难重现 (因为线程调度的无序性,某些bug的出现依赖于某种特定的线程执行时序) 。
增加更多的资源消耗
除了CPU执行上下文切换的消耗以外,线程的执行还将有其他一些资源的消耗,比如:内存同步的开销 (线程需要一些内存在维持线程本地栈,每个线程都有本地独立的栈用以存储线程专用数据) ,上下文切换的开销 (前面已经讲过) ,线程创建和消亡的开销,以及调度的开销 (占用操作系统的一些资源来管理和协调线程) , 我们可以创建100个线程让他们什么都不做,看看他们消耗了多少内存。
上下文切换
线程是由 CPU 进行调度的, CPU 的一个时间片内只执行一个线程上下文内的线程, 当CPU由执行线程 A 切换到执行线程 B 的过程中会发生一些列的操作, 这些操作主要有”保存线程A的执行现场“然后”载入线程B的执行现场",这个过程称之为”上下文切换 (context switch)",这个上下文切换过程并不廉价, 如果没有必要, 应该尽量减少上下文切换的发生。
多数人认为使用多线程一定会比单线程执行速度快,但其实未必,因为多线程应用程序会带来额外的开销和竞争问题,他们都可能会拖慢系统的执行速度。这些因素包括: 对IO设备的竞争,对锁的竞争,以及CPU对线程执行上下文的频繁切换等。
目前流行的 CPU 在同一时间内只能运行一个线程, 超线程的处理器 (包括多核处理器) 可以同一时间运行多个线程, linux 是将多核处理器当作多个单独 CPU 来识别的。 每个进程都会分到 CPU 的时间片来运行, 当某个进程 (线程是轻量级进程,他们是可以并行运行的,并且共享地使用他们所属进程的地址空间资源, 比如: 内存空间或其他资源 ) 当进程用完时间片或者被另一个优先级更高的进程抢占的时候, CPU会将该进程备份到 CPU 的运行队列中, 其他进程被调度在 CPU 上运行,这个进程切换的过程被称作"上下文切换”, 过多的上下文切换会造成系统很大的开销。
在Linux 中可以使用 vmsta t来观察上下文切换的次数,一般来说,空闲的系统, 每秒上下文切换次数大概在 1500 以下。
引起上下文切换的原因
- 时间片用完, CPU正常调度下一个任务
- 被其他优先级更高的任务抢占
- 执行任务碰到IO阻塞,调度器挂起当前任务,切换执行下一个任务
- 用户代码主动挂起当前任务让出CPU时间
- 多任务抢占资源,由于没有抢到被挂起
- 硬件中断
参考
Author -
LastMod 2017-03-26