多線程有什麼用?
最近看了多線程講解很模糊
這麼解釋問題吧:
1。單進程單線程:一個人在一個桌子上吃菜。
2。單進程多線程:多個人在同一個桌子上一起吃菜。
3。多進程單線程:多個人每個人在自己的桌子上吃菜。
多線程的問題是多個人同時吃一道菜的時候容易發生爭搶,例如兩個人同時夾一個菜,一個人剛伸出筷子,結果伸到的時候已經被夾走菜了。。。此時就必須等一個人夾一口之後,在還給另外一個人夾菜,也就是說資源共享就會發生衝突爭搶。
1。對於 Windows 系統來說,【開桌子】的開銷很大,因此 Windows 鼓勵大家在一個桌子上吃菜。因此 Windows 多線程學習重點是要大量面對資源爭搶與同步方面的問題。
2。對於 Linux 系統來說,【開桌子】的開銷很小,因此 Linux 鼓勵大家盡量每個人都開自己的桌子吃菜。這帶來新的問題是:坐在兩張不同的桌子上,說話不方便。因此,Linux 下的學習重點大家要學習進程間通訊的方法。
--
補充:有人對這個開桌子的開銷很有興趣。我把這個問題推廣說開一下。
開桌子的意思是指創建進程。開銷這裡主要指的是時間開銷。
可以做個實驗:創建一個進程,在進程中往內存寫若干數據,然後讀出該數據,然後退出。此過程重複 1000 次,相當於創建/銷毀進程 1000 次。在我機器上的測試結果是:
UbuntuLinux:耗時 0.8 秒
Windows7:耗時 79.8 秒
兩者開銷大約相差一百倍。
這意味著,在 Windows 中,進程創建的開銷不容忽視。換句話說就是,Windows 編程中不建議你創建進程,如果你的程序架構需要大量創建進程,那麼最好是切換到 Linux 系統。
大量創建進程的典型例子有兩個,一個是 gnu autotools 工具鏈,用於編譯很多開源代碼的,他們在 Windows 下編譯速度會很慢,因此軟體開發人員最好是避免使用 Windows。另一個是伺服器,某些伺服器框架依靠大量創建進程來幹活,甚至是對每個用戶請求就創建一個進程,這些伺服器在 Windows 下運行的效率就會很差。這"可能"也是放眼全世界範圍,Linux 伺服器遠遠多於 Windows 伺服器的原因。
--
再次補充:如果你是寫伺服器端應用的,其實在現在的網路服務模型下,開桌子的開銷是可以忽略不計的,因為現在一般流行的是按照 CPU 核心數量開進程或者線程,開完之後在數量上一直保持,進程與線程內部使用協程或者非同步通信來處理多個並發連接,因而開進程與開線程的開銷可以忽略了。
另外一種新的開銷被提上日程:核心切換開銷。
現代的體系,一般 CPU 會有多個核心,而多個核心可以同時運行多個不同的線程或者進程。
當每個 CPU 核心運行一個進程的時候,由於每個進程的資源都獨立,所以 CPU 核心之間切換的時候無需考慮上下文。
當每個 CPU 核心運行一個線程的時候,由於每個線程需要共享資源,所以這些資源必須從 CPU 的一個核心被複制到另外一個核心,才能繼續運算,這佔用了額外的開銷。換句話說,在 CPU 為多核的情況下,多線程在性能上不如多進程。
因而,當前面向多核的伺服器端編程中,需要習慣多進程而非多線程。使用多線程
不用多線程
因為你有多個CPU啊,一個線程只能用一個CPU,其它的放在那兒又不會生利息。
你說你只有一個CPU?那麼多線程可以讓它假裝同時在干很多件事,也就是假裝多個CPU,當然動作會慢一點,但很多時候你更慢對不。
哦,你說你就兩個CPU為什麼要創建500個線程?誰讓你用Tomcat!
很多人答案說的是操作系統提供的多進程而不是單個程序內的多線程。
多線程使得程序內部可以分出多個線程來做多件事情,而不會造成程序界面卡死。比如迅雷等多線程下載工具就是典型的多線程。一個下載任務進來,迅雷把文件平分成10份,然後開10個線程分別下載。這時主界面是一個單獨的線程,並不會因為下載文件而卡死。而且主線程可以控制下屬線程,比如某個線程下載緩慢甚至停止,主線程可以把它強行關掉並重啟另外一個線程。
另外就是一些程序的列印功能,比如記事本、Adobe Reader,列印的時候就只能列印,無法在主界面進行操作,而Word就有「後台列印」的功能,點了列印命令之後,還可以回到主界面進行修改、保存等操作。
另外多線程除了並行完成一些任務以外,還有生產者-消費者模式。比如Windows命令行下在某個硬碟根目錄執行一個"dir/s | more"命令,前一條顯示硬碟里的所有文件,要執行很久才能執行得完,後面那條命令會把前面命令的輸出分屏顯示出來。但是執行整條命令時,會立刻有顯示,也就是說,前面一條命令輸出滿一頁內容到緩衝區,more命令就把緩衝區封死了,等用戶敲了一個鍵顯示下一屏的時候,more命令把緩衝區的內容取出並清空,前面的命令才能輸出下一屏到緩衝區。這樣的多線程使得整條命令不用等待前面的命令全部執行完才能執行下一條命令。
多線程和多進程的區別。平常指的多進程是操作系統下同時運行多個進程,比如Word和Excel同時打開,並且可以並行地同時執行一些操作。這種多進程和多線程沒什麼好比較的。可以比較的是同一個程序里的多線程和多進程。
多線程因為在同一個進程里,所以可以共享內存和其他資源,比如迅雷里10個線程一齊下載一個文件,這個文件是由進程打開的,然後10個線程都可以往裡寫入東西。如果是10個進程就不行了,操作系統不允許一個文件由兩個進程同時寫入。另外,Chrome就是一個典型的多進程程序,裡面每個標籤頁、擴展、插件都是單獨的進程,各自獨佔資源,相互隔離,一個進程出錯死掉只會影響一個頁面或者插件,再也不會出現Flash插件出錯崩潰導致整個瀏覽器崩潰的情況了。我本來有一個問題
用多程線了後,現在兩個題問了有我
使用多線程一般有兩個不同的目的:
一是把程序細分成幾個功能相對獨立的模塊,防止其中一個功能模塊阻塞導致整個程序假死(GUI程序是典型)
另一個就是提高運行效率,比如多個核同時跑,或者單核裡面,某個線程進行IO操作時,另一個線程可以同時執行。
-樓上的同學已經把這個概念說的非常簡單明了。我結合對幾百個團隊代碼靜態分析的經驗說一說可能存在的問題。
同樣以吃飯舉例子,假設很多人需要吃飯吃飯,桌子不夠,那麼桌子就是緊缺資源。單線程就是整個餐廳只有一個單人桌,這個人吃完了,下一個人輪上。但大餐館用的可能是八仙桌(好吧我比較喜歡這種古代的方正桌子),同時能容納八個人吃飯,這就是多線程:從一次一個變成了一次多個或者多次多個。如何安排吃飯順序對程序員來說是個巨大的挑戰,主要問題在於對資源-桌子的安排上,舉例說明:
1.死鎖-大家都在等著吃飯,但需要特定條件才能開吃:桌一等著桌二的碗,桌二等著桌三的筷子,桌三呢,等著桌一的勺。於是這三桌就都不能吃飯。
2.非原子變數更新-空閑桌子的數字是要加以保護的,類似於特定人員才能修改,假如沒有保護,空桌子一會兒是四個,一會兒是五個,最終的數字往往是不正確的,服務員要被玩死-這就是多線程的加鎖操作。
還有其他幾種,就不多說了,多線程的調度和使用是一個坑,是否能用好是程序員水平高低的一個標誌。
我的理解是一個程序(載入內存被cpu執行的了就是進程了)的多個部分同時執行的話,那麼就會更快的完成,尤其是多個部分是需要協作的,這個部分出了結果,那個部分剛好執行到要用這個結果,那感覺不能更爽。之前的單核時代,cpu還要在不同部分跳來跳去的,現在的多核時代,一個cpu跑一段,爽得不能更爽。這是我學的時候寫的一篇博客,一個很簡單的例子,但是把用處說清楚了。
c# multi thread programming ,c# 多線程編程如果有操作系統的基本概念,這個就是不會模糊了。把程序想像成一個長條的0110序列在內存中,cpu在上面跑。
我從計算機發展歷史上簡單介紹一下。
一開始的計算機,只有一個處理器,處理器也沒有多核多線程的概念。乾的活都是人一條條指令安排好,依次去干。這就是最初的單任務處理器。
後來慢慢的,自然會產生有時候需要有多個事情要乾的情況。比如,有ABC三件事情,我們把他們都分成一小塊一小塊,干一會A再干一會B再干一會C。於是就誕生了最初的協作模式和搶佔模式,分時處理和實時處理。多任務模式和多任務處理器產生了,壓棧彈棧也應用了。但是最初的安排都是大家一起協調的,人為把代碼按功能分割開來。因為那時候還沒有完整操作系統概念呢。
後來,大家覺得,卧槽,這樣安排太費時費力,我們應該讓計算機自己處理這個,我們得把精力集中在干我們的正事兒上。於是,設計了操作系統來來管理資源,引入線程來作為多任務抽象。
再後來,大家覺得操作系統是好的,於是處理器的設計也開始為了便於操作系統管理而增加了更多任務管理的功能。慢慢的更多任務調度的數學模型被建立和引入,逐漸形成現在的體系。
其實計算機的歷史雖然不長,但是很有趣的。讀讀歷史,會使人了解為什麼世界是現在這個樣子而不是別的樣子。
以下列舉一些有助於理解上面這段的搜索關鍵詞,每行一組:
單任務處理器
分時 實時 搶佔 協作 多任務
操作系統發展史
8086彙編
80386彙編
實模式 保護模式
進程 線程 處理器調度
……
有用,多線程是你邁向多買內存得必經之路
打個比方:我們寢室洗手台有2個水龍頭,就是多線程。可以滿足2個人刷牙。不然排隊蛋疼。
為了講清楚多線程編程,這兒先講一個場景,
這個場景是這樣子的,山上有座廟(進程),廟裡住了很多小和尚和老和尚(線程),當然隔壁山上也有很多尼姑妹子。小和尚和老和尚們每天都需要下山挑水喝。這些個和尚有剛上山的(就是有點傻的),有比較聰明的,也有鬧過矛盾的。場景,人物呢,大概就是這麼個樣子。
俗話說的好,有人的地方就有江湖。這些個小和尚,老和尚都不是很安分,為了每天的這個挑水工作鬧了很多很多的矛盾,也犯過很多傻。
下面對挑水工作所有發生的情況做個詳述:
1)剛上山的小和尚挑水,就是比較傻的那個,和別人都不認識,每天挑水都自己一個人,一次挑一桶水,一天下來發現挑的水根本不夠喝。(串列)
2)和尚裡面有個力氣大的,和別人關係不好,每次挑水能挑三桶左右,一天下來,發現挑的水勉強夠喝。 (並發)
3)和尚裡面有幾個關係好的,力氣也比較大,每次挑水都一起去,每個人都能挑兩桶左右,一天下來,發現挑的水不僅夠喝,還有時間幫隔壁山尼姑妹子挑水。 (並行)
4)在水井裡打水,有個專門的妹子負責打水,比較傻的那個小和尚每次都盯著打水的妹子,還隨時隨地看水桶裝滿沒有(同步);當然,有傻的,也有聰明的,這個聰明的和尚在妹子打水的時候,就乘機在一旁休息,水打滿以後,妹子都過來告訴他。(非同步)
5)水井裡有一天沒水了,傻和尚看見水井裡沒水以後,在水井邊上一直等著,等有水了再挑回去(阻塞);聰明和尚呢,看見水井裡沒水了,一點都不猶豫的回去了。(非阻塞)
6)又有一天,那鬧過矛盾的兩個和尚挑水,正好狹路相逢,誰也不讓誰過去,一直僵持著。(死鎖)
7)寺廟裡廚房空間有限,每次只能進去一定數量的和尚,當廚房滿了以後,其他人只能在外面等著,直到裡面的人出來。這個實現的方法是,廚房門口掛了很多鎖,每個人進去以後都拿走一把鎖,出來以後把鎖掛上,這樣外面的人就可以知道廚房裡面人滿沒滿。(信號量)
終於編完了。。。
通過上面生動形象的描述,這個線程裡面的一些概念已經明白了。
下面解釋下多線程。
還是上面的例子,在這個寺廟裡面,如果每天都由那個新來的傻子和尚挑水喝,肯定是不行的,有的喝沒得喝咱且不說,你讓他累死了咋整。何況寺廟裡那麼些個空著的水桶那麼些個不幹活的人閑著也是閑著。
所以多線程的意思就是多個線程一起去協同完成一個任務,通過充分去共享資源來達到提升效率的一種編程思想。
當然,在這個過程中會遇到很多麻煩,比如會碰上死鎖的問題,同時去爭搶同一個資源的問題等等。
為了解決這個問題,iOS里是使用加鎖這個方法避免,當然,使用鎖,會在一定的程度上印象執行的效率,我們需要在效率和安全之間尋找一個平衡點。
充分利用現在的多核處理器,挖掘硬體上的潛力
大家講理論比較多,我來說點實際的使用場景,便於理解。
多線程常用於避免用戶等待,提高響應速度,增強用戶體驗;這種場合下,對提高整體運算速度的幫助不大。
比如,客戶端app中,需要下載一些數據的同時又能讓用戶繼續操作,這時候再開一個線程來下載數據是常見的選擇。這是iOS開發、android開發日常處理的事情。
更模塊化的編程模型和提升程序的數據吞吐量(好像是這麼說的)
Ps. 還有多線程死機更爽
多線程是用來將計算並行化的。
舉個最最最簡單的例子,程序裡面要干兩件毫不相干的事情A和B,各費時10分鐘,那單線程程序就會這樣:
A();
B();
等A完了再執行B,總共耗時20分鐘。但如果將A和B用兩個線程來做則如下:
線程A:A();
線程B:B();
等待兩個線程結束。
如果兩個線程被分配到不同的cpu上,則理論耗時共10分鐘。
說一點自己知道的,在一個程序中多線程有什麼用。如有說的不對懇請指出。
一個常見但不算典型多線程應用的場景是,web程序處理請求。每個請求的處理可能需要走以下幾步:
- 收到請求,調用處理類/函數;
- 分析請求,得知要獲取的數據;
- 連接資料庫或者讀取相關文件;
- 計算得出結果;
- 返迴響應數據。
我們知道,無論你有多少個線程,實際上最終決定並行計算量的是CPU的核心個數,只是CPU切換任務的速度對於人的感知來說相對快,所以在使用計算機時會覺得它能夠同時做好多個事情。假如一個程序只有一個線程,它每次排隊等候CPU使用時間都只有一個名額,自身的執行也要按順序一步一步走下來。前一步未完成,下一步就不會執行。實際上很多時間我們並不需要等候上一步完成,就可以先行做下一步,以達到最大化利用計算機內的各種資源(不僅僅是CPU)來最快地完成任務的目的。
在上面的例子中,最能夠反映這一點的就是連接資料庫及讀取文件的操作(尤其在讀取多個文件時),即I/O操作。單次I/O操作相對來說是比較花時間的(即開銷大),我們可以開一個新線程去連接、等候、獲取數據然後返回。同時,讓原有的線程繼續執行不需要用到I/O結果的部分。等到I/O線程返回(讀取完成的事件發生),再取得這分部數據去進行相關的計算或者操作。
另一個例子,Python中有個名為paramiko的庫,實現了ssh的功能。它通過ssh協議與遠程機器的類建立連接的Transport類就用到了多線程:
class Transport (threading.Thread, ClosingContextManager):
""" An SSH Transport attaches to a stream (usually a socket),
negotiates an
encrypted session, authenticates, and then creates stream tunnels, called
`channels &<.Channel&>`, across the session. Multiple channels can be multiplexed across a single session (and often are, in the case of port forwardings).
Instances of this class may be used as context managers. """
...
當你需要同時向多台遠程計算機傳輸文件時,可為每一台計算機建立一個Transport實例(即新開一個線程),然後同時進行傳輸。這樣程序就不需要等到一台機器完成傳輸後再去下一台機器操作了。
多線程最一般的應用是簡化程序的寫法。
比如對於IO工作而言,如果底層的API僅提供了同步操作函數,這樣一來,單線程的應用很難寫,
但是支持多線程後,完全可以把IO操作轉入線程中執行,主線程仍然可以進行正常的消息循環。
「單線程」程序
要想理解「多線程」,那麼就要先從「單線程」說起。
大家都知道工廠「流水線」作業,裡面的工序是一環扣一環的,只有前面的一道工序完成之後,才能夠啟動下一道工序。這其實和「單線程」的原理非常的相似。
在「單線程」裡面,程序的功能是順序執行的,只有前面的流程都成功執行之後,後面的流程才能夠被執行到。
「多線程」程序
「多線程」,顧名思義,就是多個「單線程」,每個線程獨立地完成相關的功能。
「多線程」的優點
「多線程」在大型軟體程序中有著很廣泛的應用,其優點如下:
第一,將原來在一個大流程中實現的功能放到了多個小流程中,程序更加的簡潔和易於閱讀。
第二,將不同的功能放到不同的線程中,提高了程序的執行效率。
第三,「多線程」使得程序的模塊化更強,有利於追蹤程序執行過程和排查問題。
總結
「多線程」和「單線程」分別對應「並行」和「串列」,是軟體開發人員必須要掌握的一種程序設計的方法。設計合理的「多線程」程序不僅邏輯清晰、易於閱讀,而且程序的執行效率高,對於軟體產品效率和質量的提升具有很重要的意義。
請參考:程序中的「多線程」
程序中的演算法
一個簡單的N皇后多線程求解例子:whatsGhost/cpp_hodgepodge
實際測試15皇后 單線程求解CPU佔用穩定25% 算了28秒。
開四個線程CPU一下佔滿100%,算了8秒完成。
用的C++11的線程。
推薦閱讀:
※為什麼一些人在使用電腦時不用殺毒軟體?
※目前機器學習的瓶頸有哪些?
※即時戰略遊戲(比如 WAR3)的 AI 是怎樣實現的?
※如何正確的學習Coursera上Andrew Ng的機器學習課程?