1. 程式人生 > >python模組之io

python模組之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系統呼叫,這個過程被稱為輪詢,輪詢檢查核心資料,直到資料被準備好,再拷貝資料到程序,進行資料處理,需要注意,拷貝資料整個過程,程序仍然是屬於阻塞的狀態。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

#服務端

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的優勢在於可以處理多個連線,不適用於單個連線

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

#服務端

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的比較如果所示: