Epoll的基本原理

2022-07-19 05:42:14 字數 3698 閱讀 5655

計算機之間的通訊一般是通過socket來進行,socket儲存的是通訊過程中必要的控制資訊。兩台計算機想要通訊首先要通過socket建立連線,然後相互讀寫資料。我們日常使用的瀏覽器其實可以看作乙個客戶端,服務端一般是由網際網路公司來運維。在瀏覽器輸入位址之後,瀏覽器會幫助我們和服務端建立連線,不斷讀寫資料。但客戶端可能不止乙個,有可能有多個,多個客戶端同時連線伺服器,而伺服器如何同時處理這些客戶端的連線,又如何維護這些連線呢?可行的方法有很多,比如同時啟動多個程序來處理,或者啟動多個執行緒進行處理。但這對於伺服器來說過於耗費資源,無法應對大量請求的場景。沒建立乙個程序都需要在計算機內部建立乙個程序的結構,分配一定的記憶體,占用一定的資源。雖然執行緒共享這些資源,但仍然無法支撐很大規模的請求。這個時候就需要一種新的技術。當然生產級的大規模請求還有更多的技術結合起來使用,這裡只介紹io多路復用。使用io多路復用的軟體比較多如redis, nginx等。

阻塞是程序排程的關鍵一環,指的是程序在等某事件(如接受網路資料)發生之前的

等待狀態,rec、select和epoll都是阻塞方法。下面是一段基礎的網路程式設計**。

# -*- coding: utf-8 -*-

# 檔名:server.py

import socket # 匯入 socket 模組

s = socket.socket() # 建立 socket 物件

host = socket.gethostname() # 獲取本地主機名

port = 8081 # 設定埠

s.bind((host, port)) # 繫結埠

s.listen(5) # 等待客戶端連線

while true:

c,addr = s.accept() # 建立客戶端連線

c.send('hello world')

c.close() # 關閉連線

核心狀態分為執行中、等待中、停止、殭屍。執行中的程序正在cpu中執行或者等待cpu分配時間片。等待中的程序在等某個事件的發生,比如網絡卡接收到新的資料傳送中斷到cpu。等待中的程序在所等待的事件沒有到來之前不會被執行,因此也不會占用cpu的資源。

如上圖所示,程序a包含了網路程式設計建立server並執行監聽的過程。執行recv時,作業系統會將程序a從工作佇列移動到該socket的等待佇列中。作業系統中只剩下程序b和程序c繼續執行。a被阻塞住等待事件的發生。如果有新的資料報到達網絡卡,會發生中斷。socket接收到資料之後,作業系統把a程序放回工作佇列繼續執行,處理資料。

服務端需要管理多個客戶端連線,而recv只能監視單個socket,這種矛盾下,人們開始尋找監視多個socket的方法。epoll的要義是高效的監視多個socket。從歷史發展角度看,必然先出現一種不太高效的方法,人們再加以改進。只有先理解了不太高效的方法,才能夠理解epoll的本質。

假如能夠預先傳入乙個socket列表,如果列表中的socket都沒有資料,掛起程序,直到有乙個socket收到資料,喚醒程序。這種方法很直接,也是select的設計思想。

為方便理解,我們先複習select的用法。在如下的**中,先準備乙個陣列(下面**中的fds),讓fds存放著所有需要監視的socket。然後呼叫select,如果fds中的所有socket都沒有資料,select會阻塞,直到有乙個socket接收到資料,select返回,喚醒程序。使用者可以遍歷fds,通過fd_isset判斷具體哪個socket收到資料,然後做出處理。

其一,每次呼叫select都需要將程序加入到所有監視socket的等待佇列,每次喚醒都需要從每個佇列中移除。這裡涉及了兩次遍歷,而且每次都要將整個fds列表傳遞給核心,有一定的開銷。正是因為遍歷操作開銷大,出於效率的考量,才會規定select的最大監視數量,預設只能監視1024個socket。

其二,程序被喚醒後,程式並不知道哪些socket收到資料,還需要遍歷一次。

那麼,有沒有減少遍歷的方法?有沒有儲存就緒socket的方法?這兩個問題便是epoll技術要解決的。

select低效的原因之一是將「維護等待佇列」和「阻塞程序」兩個步驟合二為一。如下圖所示,每次呼叫select都需要這兩步操作,然而大多數應用場景中,需要監視的socket相對固定,並不需要每次都修改。epoll將這兩個操作分開,先用epoll_ctl維護等待佇列,再呼叫epoll_wait阻塞程序。顯而易見的,效率就能得到提公升。

select低效的另乙個原因在於程式不知道哪些socket收到資料,只能乙個個遍歷。如果核心維護乙個「就緒列表」,引用收到資料的socket,就能避免遍歷。如下圖所示,計算機共有三個socket,收到資料的sock2和sock3被rdlist(就緒列表)所引用。當程序被喚醒後,只要獲取rdlist的內容,就能夠知道哪些socket收到資料。

如下圖所示,當某個程序呼叫epoll_create方法時,核心會建立乙個eventpoll物件(也就是程式中epfd所代表的物件)。eventpoll物件也是檔案系統中的一員,和socket一樣,它也會有等待佇列。

建立epoll物件後,可以用epoll_ctl新增或刪除所要監聽的socket。以新增socket為例,如下圖,如果通過epoll_ctl新增sock1、sock2和sock3的監視,核心會將eventpoll新增到這三個socket的等待佇列中。當socket收到資料後,中斷程式會操作eventpoll物件,而不是直接操作程序。

當socket收到資料後,中斷程式會給eventpoll的「就緒列表」新增socket引用。如下圖展示的是sock2和sock3收到資料後,中斷程式讓rdlist引用這兩個socket。

eventpoll物件相當於是socket和程序之間的中介,socket的資料接收並不直接影響程序,而是通過改變eventpoll的就緒列表來改變程序狀態。

當程式執行到epoll_wait時,如果rdlist已經引用了socket,那麼epoll_wait直接返回,如果rdlist為空,阻塞程序。

1 假設計算機中正在執行程序a和程序b,在某時刻程序a執行到了epoll_wait語句。如下圖所示,核心會將程序a放入eventpoll的等待佇列中,阻塞程序。

2 當socket接收到資料,中斷程式一方面修改rdlist,另一方面喚醒eventpoll等待佇列中的程序,程序a再次進入執行狀態(如下圖)。也因為rdlist的存在,程序a可以知道哪些socket發生了變化。

mysql的基本原理 Mysql 基本原理

mysql 基本原理 mysql是一種關聯式資料庫管理系統,關聯式資料庫將資料儲存在不同的表中,而不是將所有資料放在乙個大倉庫內,這樣就增加了速度並提高了靈活性 ysql是資料庫登入命令 uroot預設超級使用者登入 p 預設沒密碼 中寫密碼 mysqladmin uroot password 12...

pwm控制的基本原理 PWM控制的基本原理

pwm pulse width modulation 控制 脈衝寬度調製技術,通過對一系列脈衝的寬度進行調製,來等效地獲得所需要波形 含形狀和幅值 pwm控制技術在逆變電路中應用最廣,應用的逆變電路絕大部分是pwm型,pwm控制技術正是有賴於在逆 變電路中的應用,才確定了它在電力電子技術中的重要地位...

8 2 1 基本原理

乙個舞台動畫物件在包含許多舞台資訊 出現在何處,佔多大面積,處在什麼角度,是否可見 這些資訊分別儲存在動畫物件的屬性中。在 中讀取這些屬性可以了解物件的位置 大小 角度等狀態資訊 修改這些屬性可以改變物件的位置 大小 角度等狀態。如果從資料的角度去理解,動畫就是在固定時間間隔點不斷修改動畫物件某項屬...