多線程(二)使用多線程的準備知識 多線程(二)使用多線程的準備知識

1、爲何要使用多線程?
        【使計算機全部資源在執行任務的時候可以所有利用上,以提高計算機資源利用率的方式來提高系統執行效率】
  CPU的單核運行速度因爲硬件技術問題已經遇到瓶頸,而概念性的「光腦」貌似離咱們還很遙遠,如今的計算機性能提高方向是向多核發展。多核同時工做,協同完成任務。你們熟知的神威·太湖之光超級計算機總共使用了40960顆處理器,總計擁有10649600顆核心、1.31PB內存。即便是目前市場上的主流家用電腦也通常達到四核心八線程的配置標準。那麼對於這些多核的CPU,在開發軟件的時候就不得不考慮如何充分利用上每個核的性能,以致於使系統運行的效率更高。

2、CPU是執行的是線程任務仍是進程任務?
        【CPU執行的是線程中定義的任務】
        進程是對內存資源的抽象,線程是對執行任務的抽象。CPU執行的是線程任務,和進程沒有任何關係。因此,CPU中的核在任意時間點只能執行某一個線程的任務,具體執行哪一個線程就要看操做系統的任務調度策略。在單核多線程任務中,操做系統會把CPU資源按照時間片劃分,根據線程的優先級選擇線程進行執行任務。

3、程序中線程的數量控制在覈數的1~2倍對嗎?
        【不對!】 html

         左圖爲工做時win10 四核八線程 線程數: 2094。右圖爲閒置centos7  單核 線程數 :127 。線程數量遠遠超過CPU核心數量的上百倍。centos

 
        因此在開發程序過程當中,若是不是線程開啓機制錯誤,就不會產生成上萬級別的線程致使線程切換浪費資源,而幾百個線程切換對CPU來講還不至於產生過多的資源消耗。
             線程開啓機制錯誤例子:socket每接收一個請求便建立一個線程執行任務。這種狀況下,很容易的便能開啓上千上萬個線程(在工做中遇到過)。
4、線程頻繁切換會耗費資源?
        【消耗資源確定會,可是消耗的資源通常狀況下不必重視,當須要去重視的時候你就不會在看本文了】
        線程消耗一定會耗費計算機資源,影響系統的執行效率。可是這種級別的資源浪費還不必引發關注去考慮優化,隨便優化一個SQL查詢就遠遠比優化線程切換性能提高的多。
        
    測試:
        計算任務:計算1億次 f(i)=(i * 10000.56) / 200 (i從1循環到10000)  每組數據測試4次。
        電腦配置: 四核八核心CPU 8G內存 win10系統(測試過程當中運行的有其它程序,但整個過程當中沒有新的應用程序開啓或者關閉。測試先後計算機進程數102左右,線程數210左右)
        數據以下:單位s
                1線程執行10000 * 10000次相同任務運算時間:0.043584183000000006
                1線程執行10000 * 10000次相同任務運算時間:0.03411422
                1線程執行10000 * 10000次相同任務運算時間:0.033755275
                1線程執行10000 * 10000次相同任務運算時間:0.037857329
                
                10線程執行10000 * 1000次相同任務運算時間:0.020971566
                10線程執行10000 * 1000次相同任務運算時間:0.020400791
                10線程執行10000 * 1000次相同任務運算時間:0.043275417000000004
                10線程執行10000 * 1000次相同任務運算時間:0.020918537
               
                50線程執行10000 * 200次相同任務運算時間:0.041526313
                50線程執行10000 * 200次相同任務運算時間:0.028923265
                50線程執行10000 * 200次相同任務運算時間:0.020633701000000003
                50線程執行10000 * 200次相同任務運算時間:0.01057820000000002

                
                100線程執行10000 * 100次相同任務運算時間:0.034126764000000004
                100線程執行10000 * 100次相同任務運算時間:0.036614853
                100線程執行10000 * 100次相同任務運算時間:0.060594536000000004
                100線程執行10000 * 100次相同任務運算時間:0.046860865
                
                500線程執行10000 * 20次相同任務運算時間:0.054617363
                500線程執行10000 * 20次相同任務運算時間:0.090330437
                500線程執行10000 * 20次相同任務運算時間:0.060385270000000005
                500線程執行10000 * 20次相同任務運算時間:0.06421362700000001
                
                1000線程執行10000 * 10次相同任務運算時間:0.101977442
                1000線程執行10000 * 10次相同任務運算時間:0.09040313700000001
                1000線程執行10000 * 10次相同任務運算時間:0.094736125
                1000線程執行10000 * 10次相同任務運算時間:0.09127384000000001
                
                2000線程執行10000 * 5次相同任務運算時間:0.16429143000000002
                2000線程執行10000 * 5次相同任務運算時間:0.18807325200000002
                2000線程執行10000 * 5次相同任務運算時間:0.16652977000000002
                2000線程執行10000 * 5次相同任務運算時間:0.18108197
                
                
                5000線程執行10000 * 2次相同任務運算時間:0.44204793600000003
                5000線程執行10000 * 2次相同任務運算時間:0.484968116
                5000線程執行10000 * 2次相同任務運算時間:0.405066727
                5000線程執行10000 * 2次相同任務運算時間:0.42432967400000005
                
                
                10000線程執行10000 * 1次相同任務運算時間:1.453686674
                10000線程執行10000 * 1次相同任務運算時間:1.307516071
                10000線程執行10000 * 1次相同任務運算時間:1.5121169970000001
                10000線程執行10000 * 1次相同任務運算時間:1.332141795
                

由數據中能夠看出,在程序開啓1-50個線程時,執行時間在降低,10-1000個線程以內,執行時間都在同一個量級,超過一千線程以後,時間提高一個量級。所以,粗略來看 1000個如下線程切換並不會浪費大量系統資源。在程序中若是線程開啓機制正確,同時使用到線程池,那麼系統優化瓶頸就不會在線程切換的問題上。不必在這個角度考慮系統優化的問題。
測試代碼以下:多線程

 //scala2.12.12 jdk1.8
  def showNCPUTime(): Unit = {
   //測試過程當中調整threadNum,inner 這兩個參數,同時保證二者之積不變 inner * theradNum =10000
  val threadNum
= 2000 val inner = 5 //固定不變 val top = 10000 val state = new CountDownLatch(threadNum) var threads = new Array[Thread](threadNum) for (time <- (0 until threadNum)) { val thread = new Thread(new Runnable { override def run(): Unit = { for (i <- (1 to top)) { for (j <- (1 to inner)) { //i 每次都是從1 到 1000000 val temp = (i * 105300.56) / 200 } } state.countDown() } }) threads(time) = thread } var startTime = System.nanoTime for (time <- (0 until threadNum)) { threads(time).start() } state.await() val endTime = System.nanoTime println(threadNum + "線程執行" + top + " * " + inner + "次相同任務運算時間:" + (endTime - startTime) * 0.000000001) }

 
5、使用多線程的難點在哪裏?
         多線程的難點在於共享數據讀寫順序的問題,保證多個線程對同一數據的操做不會產生混亂。
        程序中流動的都是數據,程序影響的也都是數據。在多個線程同時訪問共享數據的時候,因爲線程讀取/寫入的時機不對而致使數據出錯,進而影響業務。socket

 

下面的問題涉及到操做系統底層知識,列出來只是爲了引發讀者的思考,再也不回答,以避免誤人誤己。
6、對於多核CPU,線程任務是如何分配到每一個核上面的?
7、單核CPU任務調度策略。在多個線程中,操做系統是如何選取其中某個線程分配給CPU執行的?選取規則是什麼?
8、線程切換耗費資源,那麼都耗費在什麼地方?掛起一個線程的時候操做系統都進行了哪些操做?
9、操做系統開啓一個新線程須要執行哪些步驟?計算機可以開啓的最大線程數是多少?JVM可以開啓的最大線程數是多少?他們和內存的大小有什麼關係?ide

=============================================post

原文連接:多線程(二)使用多線程的準備知識 轉載請註明出處!性能

=============================================測試

 

-----end優化

相關文章
相關標籤/搜索