python--IO模塊


IO模塊

一 IO模型 分為:

1 阻塞IO (accept recv)

2 非阻塞IO

3  IO多路復用(監聽多個鏈接)

4 異步IO

5 驅動信號模型(不經常使用)

 

1 阻塞IO (blocking IO)

特點:全程阻塞(進程不能干其他的事兒)

當用戶進程調用了recvfrom這個系統調用,kernel就開始了IO的第一個階段:准備數據。對於network io來說,很多時候數據在一開始還沒有到達,這個時候kernel就要等待足夠的數據到來,而在用戶進程這邊,整個進程會被阻塞。

當kernel直等到數據准備好了,他就會將數據從kernel中拷貝到用戶內存,然后kernel返回結果,用戶進程才解除block的狀態,重新運行起來。

 

2 非阻塞IO(non-blocking IO)

特點:發送多次系統調用

優點:wait for data時無阻塞

缺點:多次系統調用,消耗,不能第一時間拿取數據

兩個階段:wait for data非阻塞

              cope data是阻塞的

注意:在網絡IO時候,非阻塞IO也會進行recvfrom系統調用,檢查數據是否准備好,與阻塞IO不一樣,”非阻塞將大的整片時間的阻塞分成N多的小的阻塞,所以進程不斷地有機會’被CPU光顧’”。即每次recvfrom系統調用之間,cpu的權限還在進程手中,這段時間可以做其他事情。

也就是說非 阻塞的recvfrom系統調用,進程並沒有被阻塞,內核馬上返回給進程,如果數據還沒有准備好,此時會返回一個error。進程在返回之后,可以干點別的事情,然后在發起recvfrom系統調用,重復上面的過程。不斷重復進行recvfrom系統調用,這個過程被稱為輪詢,輪詢檢查內核數據,直到數據被准備好,再拷貝數據到進程,進行數據處理,需要注意,拷貝數據整個過程,進程仍然是屬於阻塞的狀態。

#服務端
import socket
sk=socket.socket()
sk.bind(("127.0.0.1",8000))
sk.listen(5)
sk.setblocking(False)
while True:
    try:
        print("waiting.........")
        conn,addr=sk.accept()
        print("++++",conn)
        data=conn.recv(1024)
        print(data.decode("utf8"))

    except Exception as e:
        print(e)
        time.sleep(4)

#客戶端
import time
import socket
sk=socket.socket()
sk.connect(("127.0.0.1",8000))
while True:
    data=input(">>")
    sk.send(data.encode("utf-8"))
    time.sleep(2)



執行結果:
waiting.........
[WinError 10035] 無法立即完成一個非阻止性套接字操作。
waiting.........
[WinError 10035] 無法立即完成一個非阻止性套接字操作。
waiting.........
[WinError 10035] 無法立即完成一個非阻止性套接字操作。
waiting.........

  

3 IO多路復用(IO multiplexing)

特點:1全程阻塞(wait for data, copy data)

        2 能監聽多個文件描述符

          實現並發

select, epoll,poll

select發起系統調用(監聽多個連接 實行並發)

 對於文件描述符(套接字對象):

1 是一個非零整數,不會變

2 收發數據的時候,對於接收端而言,數據先到內核空間,然后通過copy到用戶空間,同時,內核空間數據清空。

IO multiplexing這個詞可能有點陌生,但是如果說select,epoll,大概就都能明白了,有些地方也稱這用IO方式為event driven IO。我們知道,select/epoll的好處就在於單個process就可以同時處理多個網絡連接的IO,它的基本原理就是selet/epoll這個function會不斷的輪詢所有的socket,當某個socket有數據到達了,就通知用戶進程。

當用戶進程調用了select,那么整個進程會被block,而同時,kernel會”監視”所有select負責的socket,當任何一個socket中的數據准備好了,select就回返回。這個時候用戶進程再調用read操作,將數據從kernel拷貝到用戶進程。

需要使用兩個system call(select和recvfrom),而blocking IO只調用了一個system call(recvfrom)。

注意1:select函數返回結果中如果有文件可讀了,那么進程就可以通過調用accept()或recv()

來讓kernel將位於內核中准備到數據copy到用戶區。

注意2:select的優勢在於可以處理多個連接,不適用於單個連接

#服務端
import socket
import select
sock=socket.socket()
sock.bind(("127.0.0.1",8000))
sock.listen(5)

# sock.setblocking(False)
inputs=[sock,]
while True:
    r,w,e=select.select(inputs,[],[]) #監聽有變化的套接字,

    for obj in r:
        if obj==sock:
            conn,addr=obj.accept()
            inputs.append(conn)  #l=[sock,conn]
        else:
            data=obj.recv(1024)
            print(data.decode("utf8"))
            send_data=input(">>>")
            obj.send(send_data.encode("utf8"))



#客戶端
import socket
sock=socket.socket()
sock.connect(("127.0.0.1",8000))

while True:
    data=input(">>>")
    sock.send(data.encode("utf8"))
    res=sock.recv(1024)
    print(res.decode("utf8"))

sock.close()

  

4 異步IO(Asynchronous I/O)

特點:全程無阻塞

用戶進程發起read操作之后,立刻就可以開始去做其他的事兒,從另一方面,從kernel的角度,當它收到一個asynchronous read 之后,首先它會立刻返回,所以不會對用戶進程產生任何block,然后,kernel會 數據准備完成 ,然后將數據拷貝到用戶內存,當着一切都完成之后,kernel就給用戶進程發送一個signal,告訴它read操作完成了。

 

同步阻塞:包括(阻塞IO,非阻塞IO,IO多路復用)

異步阻塞:無阻塞 包括(異步IO)

各個IO  Model的比較如果所示:

 


免責聲明!

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



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