2014-11-05 78 views
0

我有兩個版本的Python編寫的簡單套接字服務器。 第一個版本使用epoll + nonblocking aproach,並且似乎比阻塞套接字+超時的服務器版本要慢。epoll +非阻塞套接字慢於阻塞+超時?

非阻塞服務器產生10個孩子和孩子在套接字上進行接受。在這種情況下,所有的孩子都得到EPOLLIN通知,但只有一個孩子可以做 接受,所有其他孩子都會得到EAGAIN,這被「除外」忽略。

--- server-nonblocking.py ---

import socket, time, os, select 

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
sock.bind(('127.0.0.1', 10000)) 
sock.listen(512) 
sock.setblocking(False) 


for _ in range(0,10): 

    pid = os.fork() 
    if pid == 0: #in child 
     poll = select.epoll() 
     poll.register(sock.fileno(), select.EPOLLIN) 

     while True: 
      events = poll.poll(3) # listening for events with 2 sec timeout 
      for fileno, event in events: 
       if event & select.EPOLLIN: # there is data on socket available 
        print("EPOLLIN in PID: " + str(os.getpid())) 
        try: 
         clientsock, addr = sock.accept() 
         clientsock.close() 
         print("accepted and closed in PID: " + str(os.getpid())) 
        except: 
         pass 


# we are in parent process, keep it live 
while True: 
    time.sleep(10) 

阻塞服務器也滋生10個孩子,但在監聽套接字而是使用超時,超時由except塊攔截並忽略:

--- server-blocking.py ---

import socket, time, os, select 

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
sock.bind(('127.0.0.1', 10000)) 
sock.listen(512) 
sock.settimeout(5) 


for _ in range(0,10): 

    pid = os.fork() 
    if pid == 0: #in child 
     while True: 
      try: 
       clientsock, addr = sock.accept() 
       clientsock.close() 
       print("accepted and closed in PID: " + str(os.getpid())) 
      except: 
       pass 


# we are in parent process, keep it live 
while True: 
    time.sleep(10) 

和她e是客戶。它只在環路中連接到服務器並關閉連接。 20秒後。循環將被中斷。

--- client.py ---

import socket, time, select, sys 

i = 1 
td = time.time() 
while True: 
    print("loop " + str(i) + ", time: " + str(time.time() - td)) 
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    s.connect(('localhost',10000)) 
    s.setblocking(False) 
    s.close() 
    i += 1 
    if time.time() - td >= 20: 
     break 

這裏是兩臺服務器的結果:

blocking: 
loop 137670, time: 19.99994468688965 

non-blocking: 
loop 94051, time: 19.10340452194214 

阻塞服務器可以處理方式比非更多的連接阻止服務器。當客戶端使用非阻塞版本, 我可以看到循環上的一些延遲。

有人可以解釋這種行爲嗎?爲什麼在epoll +非阻塞循環中有一些延遲?

謝謝!

回答

1

epoll()對於(來自手冊頁,epoll(2))是有用的:監視多個文件描述符以查看它們中的任何一個上是否可能有I/O。

您正在使用epoll()來監視一個文件描述符。這在上下文切換方面增加了一堆開銷;每個孩子都必須調用epoll_create(),epoll_ctl()和epoll_wait()。接着!他們都被喚醒了每一個新的連接。接着!他們中的大多數都會因接受而失敗。

在阻塞版本中,可能只有一個孩子被喚醒。