談單進程(單線程)與單進程(多線程)程序設計


http://blog.csdn.net/pecywang/article/details/8682431

本文單進程指單進程(單線程)模式;單線程也指單進程單線程;多線程指單進程(多線程模式),下同。

 

最近在B部門做項目,用到的平台框架都是基於單進程模式的,在以前的A部門做過的項目都是多線程模式的,在使用的過程中,也思考了一些問題,引發了對這兩種類型的線程的對比和自己的一些看法(僅是個人觀點)。

先講下單進程模式和多線程模式的優劣:

1.單進程開發簡單;多線程開發復雜

2.單進程在處理高並發時一般采用多啟動進程的方式;多線程僅需啟動多個線程。進程的切換開銷比線程大

3.多進程之間如果有信息通信則相對多線程效率較低,因為多線程屬於同一地址空間的訪問,效率相對較高(暫不涉及鎖等一致性策略的影響)

4.多進程穩定好,一個進程死了不影響其他進程;多線程中,任意一個出現問題,將影響到所有。

5。。。

 

最近的項目中使用框架app platform(后面簡稱AP框架),了解到它的實現是單進程模擬用戶空間多線程的方式,這個手法在學習計算機OS的時候都有接觸過,就是CPU時間分片,模擬用戶多任務並發。該框架也是使用了這種,它的級別不是進程間,而是進程內模擬。

研究了下,模型簡單化:請求-> 接收-> 處理 ->發送  大體框架流程如下:

 

AP框架原來的設計是完整的接收到數據包,然后調用用戶的處理代碼,最后再將數據包提交到發送隊列。這樣的話,因為是單線程,所以在處理一個遠程調用時(用戶接口),需要等待接收完整的數據,無法從用戶接口直接退出切換到主線程,那么對其他有事件到來的請求將被阻塞,不能很快的被處理,吞吐量必然會很低。對於大多數業務部門的代碼邏輯,任務都是輕量級的,最主要的瓶頸在IO上。原來的架構在IO上不能夠及時處理,導致阻塞,有了保存請求上下文(參見libpth)的方法之后,當前的請求在收發數據包未完成且需要等待時,主動調用schedule方法,保存現場,出讓cpu。對每個請求而言,它看到的是自己一直在運行,而對系統而言,掛起需等待的請求,處理另外一個數據已經到來的請求,肯定效率會更高一些,並發度也會提高很多。

實際上對於IO的設計一直是高吞吐網絡應用程序設計的關鍵,一般是采用Reactor模式,在Linux中大部分使用select或epoll,並將IO單獨交由一個或多個線程來處理,把IO和用戶邏輯分開,使得他們能高效執行。

AP框架正是有效的利用了網絡收發這段等待時間來處理其他任務,進一步提高了效率和並發度,實現上和CPU出讓時間片的方法是類似的,單線程模擬用戶多任務。

 但單線程還是單線程,即使提高了IO的收發效率,用戶的邏輯比較輕,也是存在一定問題的。AP框架作者把這個實現在單進程里面,且用戶的請求切換都是在用戶態進行的,開銷很小。作者當時也考慮過多線程的實現方法,但擔心多線程的內核態切換開銷過大,影響性能,所以沒有采用。據說也做了實驗,性能很差,所以就否定了。不過我注意到作者當時在測試時采用的模型是2個線程分別管理收發,隊列里有多少個請求就開啟多少個線程,請求和線程是1:1的,這樣當請求過多時就會導致進程內線程非常多,線程切換的開銷也會隨之變得很大。這在誰看來都是不太能夠接受的方案。

作者這里的線程1:1方案本身設計上就有問題,業務邏輯很輕,為什么把使用一個線程池(線程池線程幾個應該就可以,無需1:1)呢,當接收數據線程R,每收到部分數據時就將數據包投遞到線程池線程的隊列中,並從epoll中刪除,由線程池線程來判斷數據包是否結束(數據包完整由用戶來判斷,框架本身無法知道),如果數據包不完整,繼續投遞到R線程的epoll接收隊列。完整的數據包由線程池線程處理后直接投遞到發送線程S,這樣各司其責,收發線程只處理和IO有關的,線程池線程處理用戶邏輯。想必性能不會差到哪里去。

以上所講的內容都是在當前的多核server下的,服務器都是8核,16核甚至更多,將上面的線程分別綁定到不同的CPU上,線程間僅需較小粒度的鎖即可保證數據一致性,整體性能應該會有不錯的表現。AP框架的模式可以解決大部分問題,性能應該還是可以繼續提高。

(我沒有做測試實驗,僅是個人的理論分析,歡迎批評指正)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM