epoll +非阻塞套接字比阻塞+超时慢?

时间:2014-11-05 14:51:37

标签: python sockets fork blocking epoll

我有两个版本的用python编写的简单套接字服务器。 第一个版本使用epoll + nonblocking aproach,似乎比阻塞套接字+超时的服务器版本慢一些。

非阻塞服务器会生成10个子节点,子节点会对套接字执行接受。在这种情况下,所有孩子都会收到EPOLLIN通知,但只有一个孩子可以做 一个接受,所有其他孩子将获得EAGAIN,并且#34;除了阻止"。

--- 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个子节点,但在侦听套接字上使用超时,超时拦截超时并忽略:

--- 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)

这是客户端。它只在循环中连接到服务器并关闭连接。 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 + non-blocking的循环有一些延迟?

感谢!!!

1 个答案:

答案 0 :(得分:1)

epoll()对于(来自手册页,epoll(2))非常有用:监视多个文件描述符以查看是否有任何I / O.

您正在使用epoll()来监控一个文件描述符。这就是在上下文切换方面增加了一堆开销;每个孩子都必须调用epoll_create(),epoll_ctl()和epoll_wait()。然后!每个新连接都会被唤醒。然后!他们中的大多数都因接受而失败。

在阻止版本中,可能只有一个孩子被唤醒。