進程和線程——程序複雜皆源於此啊

CPU 大數據 文章 技術 向陽逐月 向陽逐月 2017-09-28

關於基礎的知識,在網絡可以搜索一大把的知識, 就知識而言,進程線程的概念是很容易理解的。 但是有編程經驗的人都知道,在編程的世界裡,複雜多源於多進程多線程編程。 其實寫東東最難的也是這個啦---簡單但複雜。 為了更好理解和使用進程和線程, 從兩個方面解釋:

1. 提供一個例子,來講進程線程在實際工程中的使用, 不管你是老手新手都可以看看,雖然這方面仁者見仁,智者見智,就當是拋磚引玉啦;

2. 也通過linux進程線程的實現, 對於編程老手,在於追求編程知識中,不能侷限於使用,也要了解一下系統知識,對於我們提升也是有很大幫助

----------------------例子講解-----------------------------------

這不我們的例子就來了。 最近在負責一個項目, 需求基本描述這樣的: 導入文件的數據到數據庫中, 導入的文件有如下要求(參考需求圖):

1) 用戶通過終端每次提交的數據在20M以上, 且用戶提交的時間相對集中;

2) 提交的數據必須在提交的時候,檢查數據的合法性。對於不合法的數據,及時反饋用戶重新導入;

3 ) 導入的數據不急於用作其他用途, 可以延時處理。 但是每個用戶錄入的數據必須是按照時間順序錄入。

進程和線程——程序複雜皆源於此啊

需求圖

需求已經很明白了, 服務器現在我們有一臺。 那我們就要著手擼代碼啦, 結果我們很快實現了demo版本, 高高興興的找客戶演示, 但是現實好殘酷呀, 我們的程序在提交第一份數據到服務時, 發現了我們運用確實在功能上沒有問題, 可以將文件正確提交,且導入到了數據庫, 但是處理一份數據用了不止3個小時。 客戶很生氣, 但是想只是demo版本,但是界面還是很滿意,希望我儘快提高系統效率。 這邊我們先把demo版本的流程通過時序圖呈現出來:

進程和線程——程序複雜皆源於此啊

demo實現序列圖

這時請教有經驗的老手, 提供我們這樣編程的效率慢的瓶頸: 1, 數據合法檢查,尤其在大數據時,這種檢查是很耗時的; 2. 在插入數據上應該改進, 通過批量的方式, 而不是現在逐行寫入數據(逐行寫入,需要不停的做IO打開關閉操作, 很耗系統時間, 系統中IO輸入輸出是最耗時的)。 聽了老手的經驗,我們改進流程(第一版時序圖)

進程和線程——程序複雜皆源於此啊

第一版時序圖

有了上次的教訓,我們沒有急著找客戶演示,我們成果。雖然我們做了功能的測試,效率確實提高了不少, 現在寫入數據庫數據由原來不止3個小時,降低到了現在6分鐘; 在找客戶前,自己做了一次模擬多用戶測試,發現嚴重的問題,當用戶數增加時, 整個系統效率急速下降, 並不能支持客戶的要求。 鬱悶的我們只能再找老手,再次指導我們工作。 老手就是老手, 讓我們先提供了兩條數據: 1. 文件合法檢查耗時數據(大概用時2分鐘); 2. 文件數據寫入數據庫耗時(大概3.5分鐘); 剩下耗時花在文件上傳上來。 然後老手給我們修改一下第一版時序圖, 提供了第二版時序圖:

進程和線程——程序複雜皆源於此啊

第二版時序圖

通過編碼實現了此次改版後的需求開發, 通過對多用戶測試, 終於滿足了客戶用戶需求; 通知客戶來驗收, 客戶也很滿意。我們拿到客戶最後付我們費用。 我們在項目最後, 應該總結一下項目, 提高團隊編程能力, 大家最終得出結論如下:

1. 這次效率提升,最明顯的是數據庫寫入, 在大數據寫入時, 應該使用批量寫入,而不是單個插入,耗時相當大;

2. 在單個程序執行上, 第一版時序圖實現上是最高效的; 但是在多CPU下, 單程序高效並不意味整個系統最高效的;

3. 多線程可以充分利用多CPU併發能力, 提高數據的吞吐率,拉昇整個服務器的執行效率; 但也不是線程越多越好, 當線程數量(一般不要超過2倍CPU)超過一定數量後, 反而會嚴重降低系統的性能。這個時候可以考慮增加硬件來解決。(線程切換,也是好消耗時間的)

4. 當併發執行時,往往由於沒有對競態資源做鎖保護, 會導致處理數據流失或者重複寫入,甚至於整個系統垮掉。因此在實現嚮應該找到競態資源做好鎖保護,如例子中紅色框起來的地方(屬於互斥鎖),需要注意競態資源加鎖。 當然競態資源還包含原子操作,信號量等等;

5. 在線程編程,應該儘量減少競態資源搶奪, 可能是導致性能下降的原因,也增加維護成本。 競態資源應該是快讀快寫, 避免多線程下長時間等待情況。

6. 為了提高程序的健壯性, 提高執行效率, 可以考慮將應用部署為多進程併發處理能力(佔用給多的CPU時間, 進程佔用CPU時間是比線程多的多的), 但由於進程資源不能共享。 所以對於競態資源處理能力很弱, 因此在開啟多進程,應該考慮對數據畫分區, 每個進程在自己的分區執行, 避免資源搶奪。

--------------------進程線程系統實現----------------------------

在開始講進程和線程前, 我們來先講一下C++/C語言編譯後二進制文件中包含的text、data、bss段等。其中text段是是代碼段包含的是計算機指令;data段是數據段,主要存放已經初始化的全局變量; bss也是數據段,用於存放未初始化的數據段。當我們將應用加載到系統內存的用戶空間, 就是獨立的進程運行起來,其在內存中的結構如圖(進程用戶空間分佈圖。為了說明方便,這個圖只是一個簡化圖, 如果想真正瞭解它在系統中運行狀態,需要了解的東東太多,不做拓展,在以後的文章,我們可以講解):

進程和線程——程序複雜皆源於此啊

進程用戶空間分佈

用戶進程空間

通過用戶進程空間圖, 我們可以掌握如下信息,也就知道線程和進程的主要區別啦:

1. 我們可以調用fork函數(系統API)創建進程;

2. 創建子進程,必須做進程信息copy, 需要將父進程的process信息全部複製, 同時我們複製完後,還需要將進程加載不同的段地址重新賦值;

3. 進程之間,段是不能共享的, 所以用戶空間是相互隔離,且獨立。如果進程間需要通信,必須通過系統提供的IPC機制交互;

4. 在同一進程的線程, 切換則很快,無需複製進程中段信息, 只需要在CPU中切換棧信息和代碼段入口機制即可,創建容易。且線程之間可以共享進程內所有相關段內容,資源共享;

5. 在系統的時間片進程有比線程更高的優先級和更長的運行時間。

總的來說, 進程和線程編程, 並不是說真的加快了程序的執行速度。 如果形象的比喻的話, 進程或者線程只是將原來一個人乾的活, 分解給了而倆個人或者跟多個人來執行, 然後合併結果得到最終結果而已。進程不但降低耗時,如果把所有分解的時間加起來更長了。 但是由於任務被分解成了小的任務分配給了不同的人, 最終任務完成是由小任務中花時間最長的任務決定的。 小任務比起原來的任務的話, 不但簡化了任務,也降低完成任務的時間啦。

所以一個團隊厲害也在於此,只有將一個項目合理分解成不同但相互獨立的小任務給團隊成員, 才能發揮團隊成員最好效率。總結下來提高團隊效率,兩個方面:

1. 提升團隊任務分解能力, 尤其負責系統的設計的必須要有此能力;

2. 要有好的制度化工具支撐團隊協作,能解決團隊溝通,任務分配、到任務實施的全流程工具。

相關推薦

推薦中...