<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    如何提高多線程程序的cpu利用率

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    正如大家所知道的那樣,多核多cpu越來越普遍了,而且編寫多線程程序也是件很簡單的事情。在Windows下面,調用CreateThread函數一次就能夠以你想要的函數地址新建一個子線程運行。然后,事情確實你發現創建多線程根本沒有讓程序快多少,也沒有提高多少cpu利用率,甚至可能讓cpu利用率下降。唯一能夠確定的是多線程能夠避免界面假死。為什么會是這樣的了。本文將舉一些例子和講述一些原因。


      首先,我來講一下多處理的一些知識。如下圖所示,
    SMP體系結構
      多處理器系統也只有一個待運行的線程隊列,內存中也只有一個操作系統拷貝,而且也只有一個內存系統,但是會有多個cpu同時運行不同的線程。一個cpu運行一個線程,那么上圖中的系統最多能在同一時間運行2個線程。其實,多處理系統需要掌握的知識不是這些,而是緩存一致性
      現在來解釋下什么是緩存一致性。由于,還是只有一個內存系統。所有cpu都要和這個內存系統通信,但是只有一條總線,那么這無疑會造成總線緊張,限制整體的速度了。那么,你多個cpu也沒多少意義了。解決這個問題的辦法還是利用cpu的緩存機制,學過組成原理的同學都知道,cpu的緩存命中率還是很高的,有90%以上吧。那么,我繼續利用緩存機制還是可以降低總線的頻繁使用的。但是,每個cpu都有自己的緩存。如果有2個cpu的緩存存儲的是同一內存數據的內容,其中一個cpu的緩存更新了,另外一個cpu的緩存也必須更新,這就是所謂的緩存一致性。編程多線程程序的一個很重要的一點就是避免因為緩存一致性引起的緩存更新風暴。
      現在我舉一個緩存更新風暴的例子。
    如圖所示的類定義,
    緩存一致性風暴
      鎖lockHttp和lockSsl中間只有8個字節,而絕大部分系統上一個緩存行是128個字節,那么這2個鎖很可能就處在同一個緩存行上面。那么,最壞的情況會發生什么事情了。假設處理器P1在運行一個處理http請求的線程T1,處理器P2在運行一個處理ssl請求的線程T2,那么當T1獲得鎖lockHttp的時候,鎖的內容就會改變,為了保持緩存一致性,就會更新P2的緩存。那么,T2要獲得鎖lockssl的時候,發現緩存已經失效了,就必須從內存中重新加載緩存之類。總之,這會將緩存命中率降低到90%以下,引起性能的嚴重降低。而且發生這種事情的原因是因為我們不了解硬件的體系結構。


      多cpu不能成倍提高速度的原因是任務的某些部分是必須串行處理的。比如,矩陣乘法可以分為三個部分,初始化矩陣,相乘,返回結果。這三部分第二部分可以用多線程來處理,第一部分和第三部分則是不可以的。而且第二部分必須在第一部分完成之后,第三部分必須在第一部分完成之后。那么,無論你添加多少個處理器,最快的時間都至少是第一部分和第二部分的時間之和。這個事實好像叫做Amdahl法則。
      如果使用多線程,那么就必須考慮線程同步,而線程同步又是導致速度降低的關鍵。所以下面就講述一些方法來加快多線程程序的吞吐速度。
      方法一,把一個任務分解為多個可以子任務。
      因為總有些子任務是可以并發的,多個子任務并發執行了很可能就能夠避免cpu需要io操作的完成了,而且能夠提高系統的吞吐量。
      方法二,緩存多線程的共享數據。
      當你已經在使用多線程了,很多時候必須使用共享數據。如果,數據是只讀的,那么可以在第一次獲取后保存起來,以后就可以重復使用了。但是,第一次的獲取還是無法避免的需要線程同步操作的。
      方法三,如果線程數目有限,就不要共享數據。
      做法是為每一個線程實例化一個單獨的數據,其實就是為每一個線程分配一塊數據使用。這樣沒有線程同步操作了,速度可以盡可能的提示。
      方法四,如果沒辦法確定線程數目到底有多少,那么使用部分共享吧。
      部分共享其實就是使用多個資源池代替一個資源池,資源池的數目得更加經驗來確定。如下圖所示,
    多個資源池

      最后在提一個叫做Thundering Herd的問題,該問題維基百科有定義http://en.wikipedia.org/wiki/Thundering_herd_problem。大意是,當多個線程在等待一個資源的時候,如果事件等待到了,操作系統是喚醒所有等待的線程讓它們自己去競爭資源了還是選擇一個線程把資源給它。當然喚醒所有的線程肯定開銷要大,而且所有沒有搶到資源的線程還得重新進入等待狀態,這無疑造成很多沒必要的操作,浪費了沒必要的線程上下文切換。總之,會不會存在Thundering Herd還是跟不同的操作系統有關的。萬一存在Thundering Herd了,多線程可能就沒那么好辦了。


      到現在我們知道了為什么多cpu并不能成倍提高程序的速度了。首先因為有些任務無法并行,其次即使是并行cpu之間還是有很多牽制的。本書的內容主要來自提高c++性能的編程技術一書。

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全