首页 > 编程知识 正文

线程上下文切换比进程快,线程上下文切换开销

时间:2023-05-03 08:28:20 阅读:276033 作者:176

            一、为什么要减少线程上下文切换
                当CPU从执行一个线程切换到执行另外一个线程的时候,它需要先存储当前线程的本地的数据,程序指针等,然后载入另一个线程的本地数据,程序指针等,最后才开始执行。这种切换称为“上下文切换”(“context switch”)。CPU会在一个上下文中执行一个线程,然后切换到另外一个上下文中执行另外一个线程。上下文切换并不廉价,是比较耗时的
            二、线程上下文切换发生的条件
                1.中断处理:中断分为硬件中断和软件中断,软件中断包括因为IO阻塞、未抢到资源或者用户代码等原因,线程被挂起
                2.多任务处理:每个程序都有相应的时间处理片,当前任务的时间片用完之后,系统CPU正常调度下一个任务
                3.用户状态切换:这种情况下,上下文切换并非一定发生,只在特定操作系统才会发生上下文切换
            三、上下文切换的步骤
                1.为了理解为什么上下文切换的时候会损耗性能,我们应该先看看上下文切换的过程中究竟发生了什么。在切换过程中,正在执行的进程的状态必须以某种方式存储起来,这样在未来才能被恢复。这里说的进程状态包括该进程正在使用的所有寄存器(尤其是程序计数器),和一些必要的操作系统数据。保存进程状态的数据结构叫做“进程控制块”(PCB,process control block);
                2.PCB通常是系统内存占用区中的一个连续存区,它存放着操作系统用于描述进程情况及控制进程运行所需的全部信息,它使一个在多道程序环境下不能独立运行的程序成为一个能独立运行的基本单位或一个能与其他进程并发执行的进程。
                上下文切换的具体步骤是(假设当前进程是进程A,要切换到的下一个进程是进程B):
                    1.保存进程A的状态(寄存器和操作系统数据);
                    2.更新PCB中的信息,对进程A的“运行态”做出相应更改;
                    3.将进程A的PCB放入相关状态的队列;
                    4.将进程B的PCB信息改为“运行态”,并执行进程B;
                    5.B执行完后,从队列中取出进程A的PCB,恢复进程A被切换时的上下文,继续执行A。
                    6.线程分为用户级线程和内核级线程。同一进程中的用户级线程切换的时候,只需要保存用户寄存器的内容,程序计数器,栈指针,不需要模式切换。但是这样会导致线程阻塞和无法利用多处理器。而同一进程中的内核级线程切换的时候,就克服了这两个缺点,但是除了保存上下文,还要进行模式切换。
                线程切换和进程切换的步骤不同。进程的上下文切换分为两步:1.切换页目录以使用新的地址空间;2.切换内核栈和硬件上下文。对于linux来说,线程和进程的最大区别就在于地址空间。对于线程切换,第1步是不需要做的,第2是进程和线程切换都要做的。所以明显是进程切换代价大。线程上下文切换和进程上下文切换一个最主要的区别是线程的切换虚拟内存空间依然是相同的,但是进程切换是不同的。这两种上下文切换的处理都是通过操作系统内核来完成的。内核的这种切换过程伴随的最显著的性能损耗是将寄存器中的内容切换出。
            四、如何减少线程上下文切换
                    1.无锁并发编程:多线程竞争锁时,会引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁,如将数据的ID按照Hash算法取模分段,不同的线程处理不同段的数据。 
                    2.CAS算法:Java的Atomic包使用CAS(compare and swap)算法来更新数据,而不需要加锁。 
                    3.使用最少线程:避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理,这样会造成大量线程都处于等待状态。 
                    4.协程:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换。

一、上下文切换
    1.即使是单核处理器也支持多线程执行代码,CPU通过给每个线程分配CPU时间片来实现这个机制。时间片是CPU分配给各个线程的时间,因为时间片非常短,所以CPU通过不停的切换线程执行,让我们感觉多个线程是同时执行的,时间片一般是几十毫秒。
    2.CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。但是在切换之前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加载这个任务的状态。所以任务从保存到再加载的过程就是一次上下文切换。
二、多线程并不一定快
三、测试上下文切换的次数和时长
    1.通过Lmbench3测量上下文切换的次数
    2.通过vmstat测量上下文切换的次数
五、避免死锁的常见方法
    1.避免一个线程同时获取多个锁
    2.避免一个线程在锁内同时占用多个资源
    3.尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制
    4.对于数据库锁,加锁和解锁必须在一个数据库连接中,否则会出现解锁失败的情况
六、资源限制的挑战
    1.什么是资源限制:资源限制是指在进行并发编程的时候,程序的执行速度受限于计算机硬件资源或软件资源。例如:硬件资源限制有带宽的上传和下载速度、硬盘读写速度和CPU的处理速度,软件资源限制有数据库的连接数和socket连接数等
    2.资源限制引起的问题:在并发编程中,将代码执行速度加快的原则是将代码中串行执行的部分变为并发执行,但是如果将某段串行的代码并发执行,因为受限于资源,仍然在串行执行,这个时候系统性能反而会变慢,因为增加了上下文切换和资源调度的时间。
    3.如何解决资源限制的问题:对于硬件资源限制,可以考虑使用资源池将资源服用。
    4.在资源限制下进行并发编程:如何在资源限制的情况下,让程序执行的更快呢?根据不同的资源限制调整程序的并发度。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。