epoll 模板

select 的問題:python

1.當進程被喚醒不清楚到底哪一個socket有數據,只能遍歷一遍linux

2.每一次select的執行,都須要將這進程,再加入到等待隊列中面試

​ 爲了防止重複添加等待隊列,當某一次操做完成時,也必須從等待隊列中刪除進程服務器

因此select最大限制被設置爲了1024 ,如此看來select連多線程都比不上多線程

因而推出了poll 和 epoll併發

poll只是簡單對select進行了優化,可是還不夠完美 ,epoll纔是最後的解決方案socket

注意:epoll僅能在linux中使用函數

案例:高併發

import socket
import select

s = socket.socket()
s.bind(("127.0.0.1",1689))
s.listen()

# 建立一個epoll對象
epoll = select.epoll()

# 註冊讀就緒事件 (有數據能夠讀取了)
# s.fileno()用於獲取文件描述符
epoll.register(s.fileno(),select.EPOLLIN)


# 存儲文件描述符與socket的對應關係
fd_sockets = {s.fileno():s}


while True:
    # 該函數是阻塞會直到你關注的事件發生
    # 返回值爲文件描述符與發生的事件類型  是一個列表 列表中是元組  第一個是描述符 第二個是事件
    for fd,event in epoll.poll():
        print("有socket 搞事情了!")
        sock = fd_sockets[fd] # 取出對應的socket對象

        # 判斷socket是服務器仍是客戶端
        if sock == s:
            # 執行對應的接收或發送
            client,addr = sock.accept()
            # 註冊客戶端的事件
            epoll.register(client.fileno(),select.EPOLLIN)
            # 將對應關係存儲到字典中
            fd_sockets[client.fileno()] = client
            print("來了一個客戶端....")
            
        elif event == select.EPOLLIN: #客戶端的處理
            data = sock.recv(1024)
            if not data:
                epoll.unregister(fd) # 註銷事件
                fd_sockets.pop(fd) # 從字典中刪除
                sock.close()  # 關閉socket
                continue

            print("%s 發來問候:%s" % (sock,data.decode("utf-8")))

            #將事件轉換爲可寫
            epoll.modify(fd,select.EPOLLOUT)
        else:
            sock.send("我是服務器  你丫是誰?".encode("utf-8"))
            # 將事件轉換爲可讀
            epoll.modify(fd, select.EPOLLIN)

epoll 如何解決select的兩個問題優化

1.epoll 把對於等待隊列的操做 與阻塞進程分開了

2.epoll 本身維護了一個等待隊列 避免了遍歷全部socket

併發:

多進程 開銷大

多線程 開銷小於進程 可是不能無限開

協程 避免線程數量達到上線的問題 本質上屬於非阻塞IO模型

IO模型 多路複用 是最好的解決方案

面試官若是問到高併發,從進程開始介紹

相關文章
相關標籤/搜索