多線程就一定能提高處理速度嗎?

每個(gè)程序員都知道,多線程能提高應(yīng)用吞吐量和處理速度。但不是每個(gè)程序員都知道為什么?

CPU運(yùn)行時(shí),通過將于運(yùn)行時(shí)間分片,通過調(diào)度來分配給各個(gè)進(jìn)程線程來執(zhí)行。因?yàn)闀r(shí)間片非常短,所以常常讓人誤以為是多個(gè)線程是同時(shí)并行執(zhí)行。

使用多線程來提高程序處理速度,其本質(zhì)是提高對CPU的利用率。主要是兩個(gè)方面

  • 柱塞等待時(shí)充分利用CPU
    當(dāng)程序發(fā)生阻塞的操作時(shí)候,例如IO等待,CPU將就空閑下來了。而使用多線程,當(dāng)一些線程發(fā)生阻塞的時(shí)候,另一些線程則仍能利用CPU,而不至于讓CPU一直空閑。
  • 利用CPU的多核并行計(jì)算能力
    現(xiàn)在的CPU基本上都是多核的。使用多線程,可以利用多核同時(shí)執(zhí)行多個(gè)線程,而不至于單線程時(shí)一個(gè)核心滿載,而其他核心空閑。

多線程就一定能提高處理速度嗎?顯示著不一定。當(dāng)程序偏計(jì)算型的時(shí)候,盲目啟動(dòng)大量線程來并發(fā),并不能提高處理速度,反而會(huì)降低處理速度。因?yàn)樵诙鄠€(gè)線程進(jìn)行切換執(zhí)行的時(shí)候會(huì)帶會(huì)一定的開銷。其中有 上下文切換開銷,CPU調(diào)度線程的開銷,線程創(chuàng)建和消亡的開銷等。其中主要是上下文切換帶來的開銷。

上下文切換的開銷,主要是來自于當(dāng)線程切換時(shí)保存上一個(gè)線程現(xiàn)場和載入下一個(gè)線程現(xiàn)場的操作。

使用空循環(huán)來模擬計(jì)算性任務(wù),看下在不同數(shù)量的線程,程序的表現(xiàn)

import java.util.ArrayList;
import java.util.List;

public class CounterDemo {


    private static final long num = 1000000000L;

    public static void splitCount(int threadNum) {
        for (long i = 0; i < num/threadNum; i++) {}
    }

    public static long getIntervalTimeToNow(long startTime) {
        return System.currentTimeMillis() - startTime;
    }

    public static void main(String[] args) throws InterruptedException {
        countWithMultithread(1);
        countWithMultithread(10);
        countWithMultithread(100);
        countWithMultithread(1000);
        countWithMultithread(10000);
    }

    private static void countWithMultithread(final int threadNum) throws InterruptedException {
        long startTime;
        Runnable splitCount = new Runnable() {
            @Override
            public void run() {
                CounterDemo.splitCount(threadNum);
            }
        };
        List<Thread> list = new ArrayList<>();
        for (int i = 0; i < threadNum; i++) {
            Thread thread1 = new Thread(splitCount);
            list.add(thread1);
        }
        startTime = System.currentTimeMillis();
        for (Thread th: list) {
            th.start();
        }
        for (Thread th: list) {
            th.join();
        }
        System.out.println(String.format("%1$9d", threadNum) + " thread need:"+String.format("%1$6d",getIntervalTimeToNow(startTime)));
    }


}

輸出結(jié)果

        1 thread need:   409
       10 thread need:    92
      100 thread need:   140
     1000 thread need:   226
    10000 thread need:   978
   100000 thread need: 10059

執(zhí)行的時(shí)候,使用vmstat 查看 CS (context switch)切換次數(shù)

vmstat 1
r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
0  0      0 2701584 151472 9676072    0    0     0    60  393  419  0  0 100  0  0
0  0      0 2701708 151472 9676084    0    0     0     0  751  751  1  0 99  0  0
0  0      0 2701708 151472 9676092    0    0     0     0  354  384  0  0 100  0  0
0  0      0 2701708 151472 9676096    0    0     0     0  435  464  0  0 100  0  0
0  0      0 2701708 151472 9676108    0    0     0    72  439  491  0  0 100  0  0
2  0      0 2701708 151472 9676128    0    0     0    32  381  453  0  0 100  0  0
1  0      0 2680344 151472 9676168    0    0     0     4 6077 4869 21  1 78  0  0
4  0      0 2664740 151472 9676180    0    0     0     0 126656 149528 17 11 72  0  0
3  0      0 2564376 151472 9676188    0    0     0     0 107107 138418 12 11 77  0  0
3  0      0 2565556 151472 9676196    0    0     0     0 128143 166234  7 14 79  0  0
4  0      0 2563056 151472 9676204    0    0     0    64 125162 163707  7 13 79  0  0
3  0      0 2567808 151472 9676208    0    0     0     0 136266 180092  7 13 80  0  0
2  0      0 2566560 151472 9676216    0    0     0     0 117768 154666  7 14 79  0  0
1  0      0 2568276 151472 9676220    0    0     0     0 107585 139240  8 13 79  0  0

當(dāng)上下文切換最多的時(shí)候每秒切換了18W+次。從輸入結(jié)果來看,線程1K,10K的時(shí)候,多線程并沒有打來處理效率的提升,反而下降了。

引起上下文切換的原因有哪些?主要有以下幾種:

  • 當(dāng)前任務(wù)的時(shí)間片用完之后,系統(tǒng)CPU正常調(diào)度下一個(gè)任務(wù);
  • 當(dāng)前任務(wù)碰到IO阻塞,調(diào)度線程將掛起此任務(wù),繼續(xù)下一個(gè)任務(wù);
  • 多個(gè)任務(wù)搶占鎖資源,當(dāng)前任務(wù)沒有搶到,被調(diào)度器掛起,繼續(xù)下一個(gè)任務(wù);
  • 用戶代碼掛起當(dāng)前任務(wù),讓出CPU時(shí)間;
  • 硬件中斷;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 又來到了一個(gè)老生常談的問題,應(yīng)用層軟件開發(fā)的程序員要不要了解和深入學(xué)習(xí)操作系統(tǒng)呢? 今天就這個(gè)問題開始,來談?wù)劜?..
    tangsl閱讀 4,322評論 0 23
  • 從哪說起呢? 單純講多線程編程真的不知道從哪下嘴。。 不如我直接引用一個(gè)最簡單的問題,以這個(gè)作為切入點(diǎn)好了 在ma...
    Mr_Baymax閱讀 2,912評論 1 17
  • word直接復(fù)制來了,格式就不改了。至于這門課怎么復(fù)習(xí),只要平時(shí)實(shí)驗(yàn)都認(rèn)真完成、報(bào)告認(rèn)真寫,平時(shí)分都很高;考試的話...
    Jozhn閱讀 4,912評論 0 8
  • 我們是如此的脆弱,以至于都不能做出自己的決定,或許我們的生存困境就是我們自己所造成的吧。我們不想為自己的決策承擔(dān)責(zé)...
    天之巔海無涯閱讀 255評論 0 0
  • 旅游這個(gè)詞,對大家來說一定不太陌生,出游為了的目的很多,但最多無非就是開闊眼界,放松心情罷了。 那么在旅游的過程中...
    魔王_Archenemy閱讀 621評論 0 0

友情鏈接更多精彩內(nèi)容