青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

S.l.e!ep.¢%

像打了激速一樣,以四倍的速度運轉,開心的工作
簡單、開放、平等的公司文化;尊重個性、自由與個人價值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

多線程服務器的適用場合

Posted on 2011-01-05 22:48 S.l.e!ep.¢% 閱讀(495) 評論(0)  編輯 收藏 引用 所屬分類: Server Program
多線程服務器的適用場合

多線程服務器的適用場合

作者: solstice_ (2 篇文章) 日期: 十一月 11, 2010 在 8:11 下午

陳碩 (giantchen_AT_gmail)

Blog.csdn.net/Solstice

2010 Feb 28

這篇文章原本是前一篇博客《多線程服務器的常用編程模型》(以下簡稱《常用模型》)計劃中的一節,今天終于寫完了。

“服務器開發”包羅萬象,本文所指的“服務器開發”的含義請見《常用模型》一文,一句話形容是:跑在多核機器上的 Linux 用戶態的沒有用戶界面的長期運行的網絡應用程序。“長期運行”的意思不是指程序 7x24 不重啟,而是程序不會因為無事可做而退出,它會等著下一個請求的到來。例如 wget 不是長期運行的,httpd 是長期運行的。

正名
與前文相同,本文的“進程”指的是 fork() 系統調用的產物。“線程”指的是 pthread_create() 的產物,而且我指的 pthreads 是 NPTL 的,每個線程由 clone() 產生,對應一個內核的 task_struct。本文所用的開發語言是 C++,運行環境為 Linux。

首先,一個由多臺機器組成的分布式系統必然是多進程的(字面意義上),因為進程不能跨 OS 邊界。在這個前提下,我們把目光集中到一臺機器,一臺擁有至少 4 個核的普通服務器。如果要在一臺多核機器上提供一種服務或執行一個任務,可用的模式有:

運行一個單線程的進程
運行一個多線程的進程
運行多個單線程的進程
運行多個多線程的進程
這些模式之間的比較已經是老生常談,簡單地總結:

模式 1 是不可伸縮的 (scalable),不能發揮多核機器的計算能力;
模式 3 是目前公認的主流模式。它有兩種子模式:
3a 簡單地把模式 1 中的進程運行多份,如果能用多個 tcp port 對外提供服務的話;
3b 主進程+woker進程,如果必須綁定到一個 tcp port,比如 httpd+fastcgi。
模式 2 是很多人鄙視的,認為多線程程序難寫,而且不比模式 3 有什么優勢;
模式 4 更是千夫所指,它不但沒有結合 2 和 3 的優點,反而匯聚了二者的缺點。
本文主要想討論的是模式 2 和模式 3b 的優劣,即:什么時候一個服務器程序應該是多線程的。

從功能上講,沒有什么是多線程能做到而單線程做不到的,反之亦然,都是狀態機嘛(我很高興看到反例)。從性能上講,無論是 IO bound 還是 CPU bound 的服務,多線程都沒有什么優勢。那么究竟為什么要用多線程?

在回答這個問題之前,我先談談必須用必須用單線程的場合。

必須用單線程的場合
據我所知,有兩種場合必須使用單線程:

程序可能會 fork()
限制程序的 CPU 占用率
先說 fork(),我在《Linux 新增系統調用的啟示》中提到:

fork() 一般不能在多線程程序中調用,因為 Linux 的 fork() 只克隆當前線程的 thread of control,不克隆其他線程。也就是說不能一下子 fork() 出一個和父進程一樣的多線程子進程,Linux 也沒有 forkall() 這樣的系統調用。forkall() 其實也是很難辦的(從語意上),因為其他線程可能等在 condition variable 上,可能阻塞在系統調用上,可能等著 mutex 以跨入臨界區,還可能在密集的計算中,這些都不好全盤搬到子進程里。

更為糟糕的是,如果在 fork() 的一瞬間某個別的線程 a 已經獲取了 mutex,由于 fork() 出的新進程里沒有這個“線程a”,那么這個 mutex 永遠也不會釋放,新的進程就不能再獲取那個 mutex,否則會死鎖。(這一點僅為推測,還沒有做實驗,不排除 fork() 會釋放所有 mutex 的可能。)

綜上,一個設計為可能調用 fork() 的程序必須是單線程的,比如我在《啟示》一文中提到的“看門狗進程”。多線程程序不是不能調用 fork(),而是這么做會遇到很多麻煩,我想不出做的理由。

一個程序 fork() 之后一般有兩種行為:

立刻執行 exec(),變身為另一個程序。例如 shell 和 inetd;又比如 lighttpd fork() 出子進程,然后運行 fastcgi 程序?;蛘呒褐羞\行在計算節點上的負責啟動 job 的守護進程(即我所謂的“看門狗進程”)。
不調用 exec(),繼續運行當前程序。要么通過共享的文件描述符與父進程通信,協同完成任務;要么接過父進程傳來的文件描述符,獨立完成工作,例如 80 年代的 web 服務器 NCSA httpd。
這些行為中,我認為只有“看門狗進程”必須堅持單線程,其他的均可替換為多線程程序(從功能上講)。

單線程程序能限制程序的 CPU 占用率。

這個很容易理解,比如在一個 8-core 的主機上,一個單線程程序即便發生 busy-wait(無論是因為 bug 還是因為 overload),其 CPU 使用率也只有 12.5%,即占滿 1 個 core。在這種最壞的情況下,系統還是有 87.5% 的計算資源可供其他服務進程使用。

因此對于一些輔助性的程序,如果它必須和主要功能進程運行在同一臺機器的話(比如它要監控其他服務進程的狀態),那么做成單線程的能避免過分搶奪系統的計算資源。

基于進程的分布式系統設計
《常用模型》一文提到,分布式系統的軟件設計和功能劃分一般應該以“進程”為單位。我提倡用多線程,并不是說把整個系統放到一個進程里實現,而是指功能劃分之后,在實現每一類服務進程時,在必要時可以借助多線程來提高性能。對于整個分布式系統,要做到能 scale out,即享受增加機器帶來的好處。

對于上層的應用而言,每個進程的代碼量控制在 10 萬行 C++ 以下,這不包括現成的 library 的代碼量。這樣每個進程都能被一個腦子完全理解,不會出現混亂。(其實我更想說 5 萬行。)

這里推薦一篇 Google 的好文《Introduction to Distributed System Design》。其中點睛之筆是:分布式系統設計,是 design for failure。

本文繼續討論一個服務進程什么時候應該用多線程,先說說單線程的優勢。

單線程程序的優勢
從編程的角度,單線程程序的優勢無需贅言:簡單。程序的結構一般如《常用模型》所言,是一個基于 IO multiplexing 的 event loop?;蛘呷缭骑L所言,直接用阻塞 IO。

event loop 的典型代碼框架是:

while (!done) {
int retval = ::poll(fds, nfds, timeout_ms);
if (retval 0) {
處理 IO 事件
}
}
}

event loop 有一個明顯的缺點,它是非搶占的(non-preemptive)。假設事件 a 的優先級高于事件 b,處理事件 a 需要 1ms,處理事件 b 需要 10ms。如果事件 b 稍早于 a 發生,那么當事件 a 到來時,程序已經離開了 poll() 調用開始處理事件 b。事件 a 要等上 10ms 才有機會被處理,總的響應時間為 11ms。這等于發生了優先級反轉。

這可缺點可以用多線程來克服,這也是多線程的主要優勢。

多線程程序有性能優勢嗎?
前面我說,無論是 IO bound 還是 CPU bound 的服務,多線程都沒有什么絕對意義上的性能優勢。這里詳細闡述一下這句話的意思。

這句話是說,如果用很少的 CPU 負載就能讓的 IO 跑滿,或者用很少的 IO 流量就能讓 CPU 跑滿,那么多線程沒啥用處。舉例來說:

對于靜態 web 服務器,或者 ftp 服務器,CPU 的負載較輕,主要瓶頸在磁盤 IO 和網絡 IO。這時候往往一個單線程的程序(模式 1)就能撐滿 IO。用多線程并不能提高吞吐量,因為 IO 硬件容量已經飽和了。同理,這時增加 CPU 數目也不能提高吞吐量。
CPU 跑滿的情況比較少見,這里我只好虛構一個例子。假設有一個服務,它的輸入是 n 個整數,問能否從中選出 m 個整數,使其和為 0 (這里 n 0)。這是著名的 subset sum 問題,是 NP-Complete 的。對于這樣一個“服務”,哪怕很小的 n 值也會讓 CPU 算死,比如 n = 30,一次的輸入不過 120 字節(32-bit 整數),CPU 的運算時間可能長達幾分鐘。對于這種應用,模式 3a 是最適合的,能發揮多核的優勢,程序也簡單。
也就是說,無論任何一方早早地先到達瓶頸,多線程程序都沒啥優勢。

說到這里,可能已經有讀者不耐煩了:你講了這么多,都在說單線程的好處,那么多線程究竟有什么用?

適用多線程程序的場景
我認為多線程的適用場景是:提高響應速度,讓 IO 和“計算”相互重疊,降低 latency。

雖然多線程不能提高絕對性能,但能提高平均響應性能。

一個程序要做成多線程的,大致要滿足:

有多個 CPU 可用。單核機器上多線程的優勢不明顯。
線程間有共享數據。如果沒有共享數據,用模型 3b 就行。雖然我們應該把線程間的共享數據降到最低,但不代表沒有;
共享的數據是可以修改的,而不是靜態的常量表。如果數據不能修改,那么可以在進程間用 shared memory,模式 3 就能勝任;
提供非均質的服務。即,事件的響應有優先級差異,我們可以用專門的線程來處理優先級高的事件。防止優先級反轉;
latency 和 throughput 同樣重要,不是邏輯簡單的 IO bound 或 CPU bound 程序;
利用異步操作。比如 logging。無論往磁盤寫 log file,還是往 log server 發送消息都不應該阻塞 critical path;
能 scale up。一個好的多線程程序應該能享受增加 CPU 數目帶來的好處,目前主流是 8 核,很快就會用到 16 核的機器了。
具有可預測的性能。隨著負載增加,性能緩慢下降,超過某個臨界點之后急速下降。線程數目一般不隨負載變化。
多線程能有效地劃分責任與功能,讓每個線程的邏輯比較簡單,任務單一,便于編碼。而不是把所有邏輯都塞到一個 event loop 里,就像 Win32 SDK 程序那樣。
這些條件比較抽象,這里舉一個具體的(雖然是虛構的)例子。

假設要管理一個 Linux 服務器機群,這個機群里有 8 個計算節點,1 個控制節點。機器的配置都是一樣的,雙路四核 CPU,千兆網互聯?,F在需要編寫一個簡單的機群管理軟件(參考 LLNL 的 SLURM),這個軟件由三個程序組成:

運行在控制節點上的 master,這個程序監視并控制整個機群的狀態。
運在每個計算節點上的 slave,負責啟動和終止 job,并監控本機的資源。
給最終用戶的 client 命令行工具,用于提交 job。
根據前面的分析,slave 是個“看門狗進程”,它會啟動別的 job 進程,因此必須是個單線程程序。另外它不應該占用太多的 CPU 資源,這也適合單線程模型。

master 應該是個模式 2 的多線程程序:

它獨占一臺 8 核的機器,如果用模型 1,等于浪費了 87.5% 的 CPU 資源。
整個機群的狀態應該能完全放在內存中,這些狀態是共享且可變的。如果用模式 3,那么進程之間的狀態同步會成大問題。而如果大量使用共享內存,等于是掩耳盜鈴,披著多進程外衣的多線程程序。
master 的主要性能指標不是 throughput,而是 latency,即盡快地響應各種事件。它幾乎不會出現把 IO 或 CPU 跑滿的情況。
master 監控的事件有優先級區別,一個程序正常運行結束和異常崩潰的處理優先級不同,計算節點的磁盤滿了和機箱溫度過高這兩種報警條件的優先級也不同。如果用單線程,可能會出現優先級反轉。
假設 master 和每個 slave 之間用一個 TCP 連接,那么 master 采用 2 個或 4 個 IO 線程來處理 8 個 TCP connections 能有效地降低延遲。
master 要異步的往本地硬盤寫 log,這要求 logging library 有自己的 IO 線程。
master 有可能要讀寫數據庫,那么數據庫連接這個第三方 library 可能有自己的線程,并回調 master 的代碼。
master 要服務于多個 clients,用多線程也能降低客戶響應時間。也就是說它可以再用 2 個 IO 線程專門處理和 clients 的通信。
master 還可以提供一個 monitor 接口,用來廣播 (pushing) 機群的狀態,這樣用戶不用主動輪詢 (polling)。這個功能如果用單獨的線程來做,會比較容易實現,不會搞亂其他主要功能。
master 一共開了 10 個線程:
4 個用于和 slaves 通信的 IO 線程
1 個 logging 線程
1 個數據庫 IO 線程
2 個和 clients 通信的 IO 線程
1 個主線程,用于做些背景工作,比如 job 調度
1 個 pushing 線程,用于主動廣播機群的狀態
雖然線程數目略多于 core 數目,但是這些線程很多時候都是空閑的,可以依賴 OS 的進程調度來保證可控的延遲。
綜上所述,master 用多線程方式編寫是自然且高效的。

線程的分類
據我的經驗,一個多線程服務程序中的線程大致可分為 3 類:

IO 線程,這類線程的的主循環是 io multiplexing,等在 select/poll/epoll 系統調用上。這類線程也處理定時事件。當然它的功能不止 IO,有些計算也可以放入其中。
計算線程,這類線程的主循環是 blocking queue,等在 condition variable 上。這類線程一般位于 thread pool 中。
第三方庫所用的線程,比如 logging,又比如 database connection。
服務器程序一般不會頻繁地啟動和終止線程。甚至,在我寫過的程序里,create thread 只在程序啟動的時候調用,在服務運行期間是不調用的。

在多核時代,多線程編程是不可避免的,“鴕鳥算法”不是辦法。

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲另类在线视频| 欧美高清在线观看| 性欧美暴力猛交另类hd| 久久一区中文字幕| 午夜激情一区| 欧美婷婷久久| 一区二区av| 亚洲黄色尤物视频| 欧美一区二区三区喷汁尤物| 欧美性做爰猛烈叫床潮| 亚洲精品美女91| 麻豆国产va免费精品高清在线| 欧美一级二级三级蜜桃| 国产精品普通话对白| 亚洲少妇自拍| 亚洲精品日韩在线观看| 欧美区在线观看| 这里是久久伊人| 亚洲免费久久| 国产精品久久久久久久久久免费 | 欧美一区91| 国产精自产拍久久久久久| 欧美在线亚洲一区| 久久国产福利| 亚洲黄色影片| 亚洲精品一区二| 欧美一区二区三区在线观看视频| 欧美刺激性大交免费视频| 久久精品30| 亚洲区国产区| 99国产精品久久久久老师| 国产精品久久久久免费a∨大胸| 午夜亚洲福利| 久久久水蜜桃| 亚洲五月婷婷| 欧美一区二区三区四区在线观看| 尤物在线观看一区| 亚洲精品免费一区二区三区| 国产精品swag| 久久在线91| 欧美日韩四区| 久久蜜桃av一区精品变态类天堂| 麻豆91精品91久久久的内涵| 亚洲丝袜av一区| 午夜久久tv| 亚洲人成网站777色婷婷| 亚洲视频一区二区免费在线观看| 韩国av一区二区| 亚洲精选在线观看| 韩国三级在线一区| 日韩网站在线观看| 激情五月婷婷综合| 亚洲最黄网站| 亚洲电影在线观看| 亚洲午夜电影网| 亚洲国产美国国产综合一区二区 | 欧美视频观看一区| 久久九九精品| 欧美日韩伦理在线免费| 老鸭窝毛片一区二区三区| 欧美三日本三级少妇三2023| 麻豆精品在线视频| 国产噜噜噜噜噜久久久久久久久| 免费一级欧美片在线播放| 国产精品久久久久久久久借妻 | 欧美一区二区三区精品 | 久久国产精品亚洲77777| 欧美成人在线影院| 久久精品国产精品亚洲| 欧美视频亚洲视频| 欧美国产日韩一区二区| 国产亚洲亚洲| 亚洲在线免费观看| 亚洲天天影视| 欧美精品一卡| 欧美激情一区二区三区在线视频观看 | 亚洲一区三区电影在线观看| 亚洲精品一区二区三区婷婷月 | 亚洲夫妻自拍| 狠狠色丁香久久婷婷综合丁香 | 亚洲第一精品影视| 午夜精品一区二区三区在线播放| 亚洲性夜色噜噜噜7777| 欧美精品黄色| 亚洲国产欧美久久| 亚洲黄色在线看| 久久亚洲精品一区二区| 久久人人97超碰精品888| 国产日韩欧美在线播放不卡| 亚洲欧美日韩精品在线| 午夜精品一区二区三区四区| 欧美性大战久久久久| 亚洲视频视频在线| 性做久久久久久久免费看| 国产精品日韩二区| 亚洲欧美成人在线| 久久久久国产精品人| 国产一区二区三区的电影| 久久国产欧美日韩精品| 葵司免费一区二区三区四区五区| 国产在线观看一区| 久久免费视频一区| 亚洲国产天堂网精品网站| 亚洲国产精品成人| 欧美日本在线视频| 在线综合亚洲| 欧美在线观看日本一区| 狠狠v欧美v日韩v亚洲ⅴ| 久久天堂成人| 亚洲欧洲免费视频| 亚洲欧美韩国| 国产亚洲欧美一级| 麻豆久久久9性大片| 亚洲精品乱码| 午夜免费电影一区在线观看| 国内精品嫩模av私拍在线观看| 久久综合九色99| 亚洲日本欧美天堂| 欧美诱惑福利视频| 亚洲国产精品专区久久| 欧美日韩国产精品自在自线| 亚洲男人天堂2024| 欧美福利一区| 亚洲素人一区二区| 国产一区二区三区奇米久涩 | 欧美日韩亚洲一区二区三区四区| 一区二区三区国产| 久久久久久久久久久久久久一区 | 久久久久久久欧美精品| 亚洲人成在线观看| 国产九九视频一区二区三区| 麻豆av一区二区三区| 亚洲一区二区三区精品在线观看| 蜜桃av久久久亚洲精品| 亚洲永久免费视频| 亚洲激情二区| 国产午夜精品美女毛片视频| 欧美黄色网络| 欧美专区亚洲专区| 亚洲视频国产视频| 亚洲国产成人精品女人久久久 | 久久九九久久九九| 欧美黄在线观看| 亚洲天堂免费在线观看视频| 久久久www成人免费精品| 999在线观看精品免费不卡网站| 国产欧美高清| 欧美日韩免费观看一区三区| 久久精品国产一区二区三| 日韩亚洲综合在线| 蜜桃久久精品乱码一区二区| 亚洲伊人网站| 日韩视频免费在线| 精品av久久707| 国产欧美日韩中文字幕在线| 欧美激情亚洲国产| 久久综合一区| 欧美在线综合视频| 在线亚洲一区二区| 亚洲精品欧美极品| 欧美大片专区| 开元免费观看欧美电视剧网站| 亚洲主播在线观看| 一区二区三区视频在线播放| 亚洲国产精品成人| 伊人影院久久| 国产一区二区三区在线观看视频| 国产精品成人免费| 欧美久久在线| 免费视频久久| 久热精品在线视频| 久久久久久久尹人综合网亚洲| 午夜精品一区二区三区在线播放 | 欧美韩日视频| 久久久亚洲人| 欧美在线影院在线视频| 欧美在线啊v一区| 性久久久久久久久久久久| 亚洲欧美日韩爽爽影院| 亚洲亚洲精品三区日韩精品在线视频| 亚洲人成人一区二区在线观看| 欧美成人免费全部| 欧美国产精品久久| 亚洲第一福利社区| 亚洲日本欧美| 一区二区三区四区蜜桃| 亚洲丝袜av一区| 亚洲女同性videos| 欧美在线观看视频| 久久裸体艺术| 免费日韩视频| 欧美日韩一区二区三区免费看| 欧美午夜不卡视频| 国产日本欧美一区二区三区在线| 国产欧美日韩综合一区在线播放| 国内精品视频在线观看| 亚洲激情啪啪| 一区二区三区久久网| 欧美一级黄色录像| 免费一区视频|