精华内容
下载资源
问答
  • 线程切换开销

    2020-09-15 23:04:57
    从单线程应用到多线程应用带来的不仅仅是好处。也会带来开销。不要仅仅在一个应用中使用多线程仅仅是因为你能够(会)使用多线程。你应该能确定使用多线程带来的好处要远远多于它带来...线程切换开销 当一个cpu从一个线

    从单线程应用到多线程应用带来的不仅仅是好处。也会带来开销。不要仅仅在一个应用中使用多线程仅仅是因为你能够(会)使用多线程。你应该能确定使用多线程带来的好处要远远多于它带来的花销。如果不能够确定,那么请尝试测量应用的性能和响应性,不仅仅是猜测。

    更复杂的设计

    尽管多线程应用的某些部分要比单线程应用更加简单,但是应用的另一些部分会变得更加复杂。当一个多线程应用访问共享数据时要特别注意。线程的交互一点也不简单。错误总是在不正确的线程同步中产生,而且很难发现、重现、修复。

    线程切换开销

    当一个cpu从一个线程切换到另一个线程时,cpu需要保存当前线程的本地数据,程序当前的指针等,然后加载下一个等待执行的线程的本地数据,程序指针等。这种切换被称之为上下文切换。cpu从执行一个线程切换去执行另一个线程。

    上下文切换需要花费很多资源。除非必要,你不要去切换上下文。

    你能够读更多的信息关于上下文在维基百科上面。

    增加的资源消耗

    为了启动一个线程需要消耗一些计算机的资源。而且一个线程cpu时间(?)需要一些内存来存储它的本地的栈。它也会在操作系统中占据一些资源来管理线程。尝试创建一个拥有100个线程的程序,每一个线程什么都不做,仅仅是等待,然后看看当这个应用运行的时候占据了多少内存。

    展开全文
  • 为什么用多线程或多进程? 程序的大部分耗时在等待IO上,瓶颈不在CPU上时,可以提高CPU利用率 需要集中快速处理大量数据,并且不受先后顺序影响 评论区还可补充ing 线程和线程 线程的实现可以分为两类: 用户级...

    码字不易,转载请附原链,搬砖繁忙回复不及时见谅,技术交流请加QQ群:909211071

    前言

    为什么用多线程或多进程?

    1. 程序的大部分耗时在等待IO上,瓶颈不在CPU上时,可以提高CPU利用率
    2. 需要集中快速处理大量数据,并且不受先后顺序影响
    3. 评论区还可补充ing

    线程和线程

    线程的实现可以分为两类:

    • 用户级线程:不需要内核支持而在用户程序中实现的线程,其不依赖于操作系统核心,在语言层面利用线程库提供创建、同步、调度和管理线程的函数来控制用户线程。不需要用户态/内核态切换,速度快,操作系统内核不知道多线程的存在,因此一个线 程阻塞将使得整个进程(包括它的所有线程)阻塞。由于这里的处理器时间片分配是以进程为基本单位,所以每个线程执行的时间相对减少
    • 内核线线程:又称为内核支持的线程或轻量级进程,所以需要切换到内核态。

    进程切换都需要内核态转换

    为什么进程切换比线程切换开销大?

           逻辑地址:操作系统在页表中记录了逻辑地址到物理内存地址的映射关系,有了页表就可以将逻辑地址转换为物理内存地址了。每个进程都有自己的逻辑地址,进程内的所有线程共享进程的逻辑地址。

           进程切换与线程切换的最主要区别:进程切换涉及到虚拟地址空间的切换而线程切换则不会。因为每个进程都有自己的虚拟地址空间,而线程是共享所在进程的虚拟地址空间的,因此同一个进程中的线程进行线程切换时不涉及虚拟地址空间的转换。把虚拟地址转换为物理地址需要查找页表,页表查找是一个很慢的过程,因此通常使用TLB(Translation Lookaside Buffer)来缓存页地址,用来加速页表查找。当进程切换后页表也要进行切换,页表切换后TLB就失效了,那么虚拟地址转换为物理地址就会变慢,表现出来的就是程序运行会变慢,而线程切换则不会导致TLB失效,因为线程线程无需切换地址空间,因此我们通常说线程切换要比较进程切换块,原因就在这里。

    展开全文
  • 这段时间一直在忙着秋招,一边面试,一边整理总结,在面试的过程中也会发现很问题,自己学习的时候并没有深究,导致“知其然而不知其所以然”,当面试被问到的时候,感到很可惜。其实想想也不必可惜,面试就是一个...

    这段时间一直在忙着秋招,一边面试,一边整理总结,在面试的过程中也会发现很多问题,自己学习的时候并没有深究,导致“知其然而不知其所以然”,当面试被问到的时候,感到很可惜。其实想想也不必可惜,面试就是一个查漏补缺的过程,在这个过程中发现自己的一些遗漏之处,进一步查阅资料、深入学习,对自己也是很有帮助的。

    现在对自己遇到的以及和周围的小伙伴交流的他们遇到的其中一些问题,整理下面经,必要时留下有参考意义的前辈的文章,以便后续查看。

    一、线程的上下文切换及其开销

    在一次面试时,被问到线程切换的开销指的是什么?听到这个问题的时候有点懵懵的,最后也没答出来个所以然,今天就对这个问题做一些整理。

    多线程中两个必要的开销:线程的创建、上下文切换

    线程的上下文切换概念:

    多任务系统往往需要同时执行多道作业,而作业数往往都大于机器的CPU数,然而一个单核CPU同时只能执行一项任务,操作系统的设计者巧妙地利用了时间片轮转的方式。

    1)时间片是CPU分配给各个线程的时间,时间片一般是几十毫秒。

    2)CPU通过给每个线程分配CPU时间片,并且不停地切换线程来实现多线程。因为时间片非常短,所以感觉多个线程是在同时执行。

    在当前任务执行的过程中,当操作系统分配的时间片用完后,会切换到下一个任务(即执行另外一个线程)。在切换之前,上一个任务的状态会被保存下来,下次切换回这个任务时,可以再加载这个任务的状态,任务从保存到再加载的过程就是一次上下文切换。

    时间片轮转的方式使多个任务在同一个CPU上执行变成了可能,但同时也带来了保存现场和加载现场的直接消耗。(更精确地说, 上下文切换会带来直接和间接两种因素影响程序性能的消耗。直接消耗包括:CPU寄存器需要保存和加载, 系统调度器的代码需要执行, TLB(转换检测缓冲区)实例需要重新加载, CPU 的pipeline(执行序列)需要刷掉; 间接消耗指的是多核的cache之间得共享数据, 间接消耗对于程序的影响要看线程工作区操作数据的大小)。

    由上述可知,上下文切换并不廉价,但我们可以通过一些方法减少线程上下文的切换。

    减少上下文切换的方法:
        
            (1)无锁并发编程(详情可见https://blog.csdn.net/jisuanji198509/article/details/80094898):
                多线程锁竞争导致的上下文切换时间成本远远大于线程持有锁的性能损耗,所以在使用多线程处理数据时,可以采用一些策略来避免使用锁。
                常见的策略:将数据按照id的哈希值进行切分,不同的线程处理不同段的数据。

    还有一种无锁并发编程的方法就是,利用队列这一数据结构结合函数指针,将指向对应线程的函数指针依次入队,当调用相应的线程时,出队头的函数指针,通过函数指针调用其指向的函数线程去执行。
     
            (2)锁分离技术:
                举例:ConcurrentHashMap
                
            (3)CAS算法
                java的Atomic包使用CAS算法来更新数据,而不需要加锁。
     
            (4)使用最少的线程
                避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理,这样会造成大量线程都处于等待状态。
     

    二、弱引用智能指针Weak_ptr的用法

    以前学习智能指针这块的时候只特别关注了强智能指针shared_ptr的用法,对于弱引用智能指针weak_ptr只知道它不能单独使用必须可以结合强智能指针来使用。

    weak_ptr 是一种不控制对象生命周期的智能指针, 它指向一个 shared_ptr 管理的对象. 进行该对象的内存管理的是那个强引用的 shared_ptr. weak_ptr只是提供了对管理对象的一个访问手段.。

    weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少。

    weak_ptr 使用

    (定义在 memory 文件中(非memory.h), 命名空间为 std.)

    std::shared_ptr<int> sp(new int(10));
    std::weak_ptr<int> wp(sp);
    wp = sp;
    printf("%d\n", wp.use_count()); // 1
    wp.reset();
    printf("%d\n", wp); // 0

    // 检查 weak_ptr 内部对象的合法性.
    if (std::shared_ptr<int> sp = wp.lock())
    {
    }

    成员函数

    weak_ptr 没有重载*和->但可以使用 lock 获得一个可用的 shared_ptr 对象。注意, weak_ptr 在使用前需要检查合法性。

    expired 用于检测所管理的对象是否已经释放, 如果已经释放, 返回 true; 否则返回 false。
    lock 用于获取所管理的对象的强引用(shared_ptr)。 如果 expired 为 true, 返回一个空的 shared_ptr; 否则返回一个 shared_ptr, 其内部对象指向与 weak_ptr 相同。
    use_count 返回与 shared_ptr 共享的对象的引用计数。
    reset 将 weak_ptr 置空。
    weak_ptr 支持拷贝或赋值, 但不会影响对应的 shared_ptr 内部对象的计数。

    使用 weak_ptr 解决 shared_ptr 因循环引有不能释放资源的问题

    使用 shared_ptr 时, shared_ptr 为强引用, 如果存在循环引用, 将导致内存泄露. 而 weak_ptr 为弱引用, 可以避免此问题。

    其原理:
      对于弱引用来说, 当引用的对象活着的时候弱引用不一定存在,仅仅是当它存在的时候的一个引用, 弱引用并不修改该对象的引用计数, 这意味这弱引用它并不对对象的内存进行管理。
      weak_ptr 在功能上类似于普通指针, 然而一个比较大的区别是, 弱引用能检测到所管理的对象是否已经被释放, 从而避免访问非法内存。
    注意: 虽然通过弱引用指针可以有效的解除循环引用, 但这种方式必须在程序员能预见会出现循环引用的情况下才能使用, 也可以是说这个仅仅是一种编译期的解决方案, 如果程序在运行过程中出现了循环引用, 还是会造成内存泄漏.


     

    展开全文
  • 多线程的线程开销

    2019-05-27 15:30:00
    多线程中两个必要的开销:线程的创建、上下文切换 创建线程: 创建线程使用是直接向系统申请资源的,对操作系统来说,创建一个线程的代价是十分昂贵的, 需要给它分配内存、列入调度,同时在线程切换的时候还要执行...

    多线程中两个必要的开销:线程的创建、上下文切换

    创建线程:

    创建线程使用是直接向系统申请资源的,对操作系统来说,创建一个线程的代价是十分昂贵的, 需要给它分配内存、列入调度,同时在线程切换的时候还要执行内存换页,CPU 的缓存被 清空,切换回来的时候还要重新从内存中读取信息,破坏了数据的局部性。

    关于资源:Java线程的线程栈所占用的内存是在Java堆外的,所以是不受java程序控制的,只受系统资源限制,默认一个线程的线程栈大小是1M(当然这个可以通过设置-Xss属性设置,但是要注意栈溢出问题),但是,如果每个用户请求都新建线程的话,1024个用户光线程就占用了1个G的内存,如果系统比较大的话,一下子系统资源就不够用了,最后程序就崩溃了。

    同样的道理在java程序中也不要随意开启新的线程,特别是高频业务尽量使用线程池,不然很容易导致内存不足,程序崩溃的问题。


     上下文切换:

    概念:
    当前任务执行一个时间片后会切换到下一个任务。在切换之前,上一个任务的状态会被保存下来,下次切换回这个任务时,可以再加载这个任务的状态,任务从保存到再加载的过程就是一次上下文切换。

    说明:
    1)时间片是CPU分配给各个线程的时间,时间片一般是几十毫秒。
    2)CPU通过给每个线程分配CPU时间片,并且不停地切换线程来实现多线程。因为时间片非常短,所以感觉多个线程是在同时执行。

    减少上下文切换的方法:

    1)无锁并发编程:
    多线程竞争锁时,会引起上下文切换,所以在使用多线程处理数据时,可以采用一些策略来避免使用锁。
    常见的策略:将数据按照id的哈希值进行切分,不同的线程处理不同段的数据。

    2)锁分离技术
    举例:ConcurrentHashMap

    3)CAS算法
    java的Atomic包使用CAS算法来更新数据,而不需要加锁。

    4)使用最少的线程
    避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理,这样会造成大量线程都处于等待状态。


    举例:

    通过减少大量WAITING的线程,来减少上下文切换次数

    # 转储堆栈信息
    jstack PID > dumpfile

    # 统计所有线程的状态
    grep java.lang.Thread.State dumpfile | awk '{print $2" "$3" "$4" "$5}' | sort | uniq -c

    如果存在大量waiting的线程,则查看dumpfile文件进行分析:
    1)如果是服务器的工作线程大量等待,则修改服务器配置文件中线程池的配置信息,然后重启查看效果。


    转载于:https://www.cnblogs.com/sunweiye/p/10930992.html

    展开全文
  • 为什么切换线程切换进程开销

    千次阅读 2019-03-29 08:16:00
     关于进程的定义有很,一个经典的定义是一个执行中程序的实例,进程是程序的动态表现。 一个程序进行起来后,会使用很资源,比如使用寄存器,内存,文件等。每当切换进程时,必须要考虑保存当前进程的状态。...
  • 多线程中两个必要的开销:线程的创建、上下文切换 上下文切换: 概念: 当前任务执行一个时间片后会切换到下一个任务。在切换之前,上一个任务的状态会被保存下来,下次切换回这个任务时,可以再加载这个任务的...
  • Java应用中线程是不是开的越越好,开多少合适,如何减少上下文切换开销?,如何写个shell脚本获取上下文切换的开销?
  • 今天先是看到多线程级别的内容,然后又看到协程的内容。 基本的领会是,协程是对异步回调方式的一种变换,同样是在一个线程内,协程通过主动放弃时间片交由其他协程执行来协作,故名协程。 而协程很早就有了,那时候...
  • 在网络或用户换机下,一个服务器通常需要接收大量不确定数量用户的并发请求,为每一个请求都创建一个进程显然行不通(系统开销大响应用户请求效率低),因此操作系统中线程概念被引进。 进程:是并发执行的程序在...
  • 线程切换比进程快

    2020-11-30 17:53:57
    我们都知道线程切换开销比进程切换的开销小,那么小在什么地方?切换的过程是怎样的? 无论是在多核还是单核系统中,一个CPU看上去都像是在并发的执行个进程,这是通过处理器在进程间切换来实现的。 操作系统...
  • 在单线程的情况, 不需要考虑多线程的调度, 上下文切换开销 , 不需要用锁, 并发数据结构. 但是多线程的情况,虽然带来了效率的提高, 也带来了安全性的问题, 活跃性问题, 但同时也会带来性能问题. 性能问题的体现有...
  • 如果是单个线程,在CPU 调用之后,那么它基本上是不会被调度出去的。...在某些场景下使用多线程是非常必要的,但多线程编程给系统带来了上下文切换,从而增加的性能开销也是实打实存在的。那么我们该如何
  • java并发线程优化之线程引入的开销

    千次阅读 2013-11-12 11:07:33
    如何让多线程优于单线程程序,很简单的一个原则:多线程并行带来的优势要优于引入多线程带来的开销。 下面来讨论多线程在哪些方面会带来开销: 1,切换上下文  产生原因举例:多线程竞争锁时被阻塞,该...
  • 多线程中两个必要的开销:线程的创建、上下文切换。下文主要讲的是上下文切换 1. 上下文切换的概念? 上下文切换是指CPU的控制权由运行任务转移到另外一个就绪任务时所发生的事件。 通俗的说,上下文切换就是从当前...
  • 多线程

    2018-08-16 08:21:55
    一、什么是多线程   线程:是可与其他指令序列并发的一个指令序列...现在编程中不能滥用多线程编写程序,因为线程同时存在太多,线程切换开销就会成几何次方增加,这时的线程反而成了降低性能的原因。过多的线程...
  • 上下文切换 (CS)是基础操作系统提供的宝贵服务。... 所需的开销和时间称为上下文切换开销。 何必呢? 随着上下文切换的增加,CPU缓存中可用的上下文数据的可能性很小,因此需要从主内存中获取,这比从...
  • 请谨慎使用多线程

    2009-01-09 23:36:00
    多线程切换开销带来的多线程程序的低效性,这促使我们认真地思考一个问题:我们是否需要多线程?何时需要多线程? 多线程的核心在于多个代码块并发执行,本质特点在于各代码块之间的代码是乱序执行的。我们的程序...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,055
精华内容 1,222
关键字:

多线程切换开销