併發模型與IO模型梳理

来源:https://www.cnblogs.com/cchust/archive/2019/08/18/11366096.html
-Advertisement-
Play Games

併發模型 常見的併發模型一般包括3類,基於線程與鎖的記憶體共用模型,actor模型和CSP模型,其中尤以線程與鎖的共用記憶體模型最為常見。由於go語言的興起,CSP模型也越來越受關註。基於鎖的共用記憶體模型與後兩者的主要區別在於,到底是通過共用記憶體來通信,還是通過通信來實現訪問共用記憶體。由於actor模型 ...


併發模型

     常見的併發模型一般包括3類,基於線程與鎖的記憶體共用模型,actor模型和CSP模型,其中尤以線程與鎖的共用記憶體模型最為常見。由於go語言的興起,CSP模型也越來越受關註。基於鎖的共用記憶體模型與後兩者的主要區別在於,到底是通過共用記憶體來通信,還是通過通信來實現訪問共用記憶體。由於actor模型和CSP模型,本人並不是特別瞭解,我主要說說最基本的併發模型,基於線程與鎖的記憶體共用模型。

     為什麼要併發,本質都是為了充分利用多核CPU資源,提高性能。但併發又不能亂,為了保證正確性,需要通過共用記憶體來協調併發,確保程式正確運轉。無論是多進程併發,還是多線程併發,要麼通過線程間互斥同步(spinlock,rwlock,mutex,condition,信號量),要麼通過進程間通信(共用記憶體,管道,信號量,套接字),本質都是為了協同。多線程和多進程本質類似,尤其是linux環境下的pthread庫,本質是用輕量級進程實現線程。下麵以網路服務為例,簡單討論下多線程模型的演進。

    最簡單的模型是單進程單線程模型,來一個請求處理一個請求,這樣效率很低,也無法充分利用系統資源。那麼可以簡單的引入多線程,其中抽出一個線程監聽,每來一個請求就創建一個工作線程服務,多個請求多個線程,這就是多線程併發模型。這種模式下,資源利用率是上去了,但是卻有很多浪費,線程數與請求數成正比,意味著頻繁的創建/銷毀線程開銷,頻繁的上下文切換開銷,這些都是通過系統調用完成,需要應用態到內核態的切換,導致sys-cpu偏高,資源並沒有充分利用在處理請求上。

     為了緩解這個問題,引入線程池模型,簡單來說,就是預先創建好一批線程,並且加大線程的復用能力,將線程數控制在一定數目內,緩解上下文切換開銷。以MySQL線程池為例,原來多線程模型是單連接單線程,現在變成單語句單線程,提高了線程復用效率。如果線程在執行過程中遇到等待(鎖等待,IO等待),那麼線程掛起,並減少活躍線程數,告知線程池系統活躍線程可能不夠,需要追加線程,然後等系統空閑時,再減少線程數目,做到根據系統負載平衡線程數目。為了做到極致,更進一步減少上下文切換開銷,引入了協程,協程只是一種用戶態的輕量線程,它運行在用戶空間,不受系統調度。它有自己的調度演算法。在上下文切換的時候,協程在用戶空間切換,而不是陷入內核做線程的切換,減少了開銷。協程的併發,是單線程內控制權的輪轉,相比搶占式調度,協程是主動讓權,實現協作。協程的優勢在於,相比回調的方式,寫的非同步代碼可讀性更強。缺點在於,因為是用戶級線程,利用不了多核機器的併發執行。簡單總結下:

單線程-->(單線程輪詢處理,太慢)
多線程-->(多線程會頻繁地創建、銷毀線程,這對系統也是個不小的開銷。這個問題可以用線程池來解決。)
線程池-->(仍然有多線程上下文切換的問題,調度由內核調度)
協程-->(應用層調度,不touch內核)

I/O模型
    linux中所有物理設備對於系統而言都可以抽象成文件,包括網卡,對應的就是套接字,磁碟對應的文件,以及管道等。因此所有對物理設備的讀寫操作都可以抽象為IO操作,典型的IO操作模型分為以下幾類,阻塞IO,非阻塞IO,I/O多路復用,非同步非阻塞IO以及非同步IO等。

IO模型分類
阻塞I/O--> 原生的read/write系統調用,預設導致線程阻塞;
非阻塞I/O -->通過指定系統調用read/write的參數為非阻塞,告知內核fd沒就緒時,不阻塞線程,而是返回一個錯誤碼,應用死迴圈輪詢,直到fd就緒;
I/O多路復用-->(select/poll/epoll),對通知事件堵塞,對於I/O調用不堵塞。
非同步I/O(非同步非阻塞)-->告知內核某個操作(讀寫I/O),並讓內核在整個操作(包括將數據複製到我們的進程緩衝區)完成後通知。

I/O多路復用
    常見的I/O多路復用主要用於網路IO場景,主要有select,poll和epoll機制。對比同步I/O,實際上是對I/O請求加了一層代理,由這些代理去監聽通知事件(是否網路包到來),然後再通知用戶去讀寫數據。這種方式也是一種阻塞I/O,代理對通知事件阻塞,這裡的代理一般指監聽線程。對比select,poll提升了最大支持文件描述符數目,從1024提升到65535,MySQL中的半同步複製還因為使用select的這個限制,導致半同步中斷的bug(鏈接)。

      對比select和poll機制,epoll通過事件表管理用戶感興趣的事件,無需反覆傳入用戶感興趣事件,處理事件通知的時間複雜度是O(1),而select,poll機制的時間複雜度是O(N)。另外select/poll只能工作在LT模式(水平觸發模式);而epoll不僅支持LT模式,還支持ET模式(邊緣觸發模式)。兩種模式的主要區別是,有數據可讀時,LT模式會不停的通知,直到數據被獲取,這種模式不用擔心通知事件丟失;ET模式只會通知一次,因此對比LT少很多epoll系統調用,效率更高。epoll對編程要求高,需要細緻的處理每個請求,否則容易發生丟失事件的情況。從本質上講,與LT相比,ET模型是通過減少系統調用來達到提高並行效率的。

libev/libeasy
      epoll很好用,但是要使用epoll,fd,signal,timer分別要採用不同的機制才能一起工作。libev第一個要做的事情就是把系統資源統一成一種調用方式。因為都需要在讀寫事件就緒後自己負責進行讀寫,也就是讀寫過程是阻塞的。libev的核心是事件處理框架,最常見的是就是一個所謂的Reactor事件處理框架和設計模式。Reactor對象負責實現主迴圈(其中有事件分離器的調用),定義事件處理介面,用戶程式向Reactor註冊事件回調的實現類(從介面繼承),Reactor主迴圈在收到事件的時候調用相應的回調函數。libeasy實現類似libev和libevent的功能,包括HTTP伺服器等,不同的是,它基於libev做了包裝,提供了同一個的資源fd和loop機制,線程池,非同步框架等實現。

AIO
說到AIO,一般是說磁碟的非同步I/O,linux早期的版本並沒有真正的AIO介面,所謂的AIO其實是多線程模擬的,在應用態完成。具體而言就是有一個隊列存儲IO請求,通過一組工作線程提取任務,併發起同步IO,待IO完成後,再通知用戶已經完成了。對於用戶而言,由於是提交IO請求後就直接返回,然後再被通知IO已經完成,所以可以認為是非同步I/O,這種非同步I/O實現機制主要指POXIS AIO,MySQL的InnoDB引擎也實現了一套類似的AIO機制。後面linux內核引入了真正的AIO,主要區別在於發起I/O調用不再是同步調用,IO請求統一在內核層面排隊,並且一次可以提交一批非同步IO請求,然後通過輪詢或者回調的方式接收完成通知即可。相比於POXIS AIO,底層有更多的IO並行,IO和CPU能充分併發,大大提升性能。在使用中,通過-lrt鏈接使用AIO庫是POXIS介面,而通過-laio鏈接使用的AIO庫是linux Native AIO介面。常用介面包括 io_setup,io_destroy,io_submit,io_cacel和io_getevents等。

同步IO:
優點:簡單
缺點:IO阻塞,無法充分利用IO和CPU資源,效率低

Native AIO:
優點:AIO可以支持一次發送多個不連續的非同步IO請求,性能更好(同步IO需要發送多次)
缺陷:需要文件系統支持O_DIRECT選項,如果不支持,io_submit實際上是“退化”成同步操作。

POSIX AIO:
優點:不依賴O_DIRECT選項,有一定的合併能力(相鄰地址的請求,可以做merge)。
缺點:併發的IO請求受限於線程數目;另外就是,可能慢速磁碟,可能導致其它新的請求沒有及時處理(工作線程數不夠了)。

參考文檔
https://cloud.tencent.com/developer/article/1349213
https://my.oschina.net/dclink/blog/287198
https://www.cnblogs.com/lojunren/p/3856290.html
https://www.ibm.com/developerworks/cn/linux/l-async/


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 首先是LRU的定義,LRU表示最近最少使用,如果數據最近被訪問過,那麼將來被訪問的幾率也更高。 所以邏輯應該是每次都要將新被訪問的頁放到列表頭部,如果超過了list長度限制,就將列表尾部的元素踢出去。 主要結構,STL中的雙向鏈表結構list。 主要操作有get,表示訪問key對應的value,此時 ...
  • 關機:halt/poweroff :立刻關機reboot :立刻重啟 shutdown -r now :立刻重啟shutdown -h 00:00 :定時重啟 now:立刻shutdown -h +num :num分鐘後重啟shutdown -c :取消命令sync :系統文件同步,關機將記憶體問價存 ...
  • Installation of the latest version of netease-cloud-music on Fedora 30 linux platform Abtract As we know, netease company pushed debian-based version ...
  • 題目如下: 求最後的輸出結果: 這道題當時沒分清楚,太菜了,結果應該這樣推出來, 首先弄清楚fork()返回值,在父進程中是一個非0數,子進程中則是0, 所以pid1可以分為兩類值非0和0, (1)pid1非0,pid2同理有兩種取值,0或者非0, (2)pid1為0,表示是子進程,則pid2同樣是 ...
  • 今天開始學習,開始做筆記,希望自己能堅持下去 參考鏈接:https://www.linuxprobe.com/chapter-04.html vim編輯器 Linux系統中通用的文本編輯器 vi的升級版本:著色 三種模式 命令模式:控制游標移動,文本複製、粘貼、刪除等操作 輸入模式:輸入文本信息 末 ...
  • sudo service network-manager stop sudo rm /var/lib/NetworkManager/NetworkManager.state sudo service network-manager start三條命令救命了!親測有用環境 Vm 15 player + ...
  • 在日常開發環境中,可能會碰到需要內網穿透的一些需求,如微信小程式的開發,為了便於開發調試,需要將內網機器對外暴露,較便捷的方式有(難易度由上往下依次繁瑣): 使用 ngrok 等類似客戶端,通過別人架設的伺服器進行內網穿透,較為靈活,可自建伺服器。 註冊一個花生殼,使用其推出的內網穿透服務,有的時候 ...
  • 配置dhcp伺服器 第一步:配置網卡 第二步: 安裝dhcp (需要先構建yum倉庫,構建yum倉庫的方法在之前的博客里有) 編寫dhcp.conf文件 進去以後會出現這個內容 需要執行下麵的內容將內容寫入 編寫成下麵的內容: 開啟dhcp服務 用windows 測試 (需要註意,在虛擬機中,win ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...