我正在使用UDP在python中进行一些线程异步网络实验。
我想了解polling和select python模块,我从未在C / C ++中使用它们。
这是为了什么?我有点理解,但在观看资源时会阻止吗?民意调查的目的是什么?
答案 0 :(得分:10)
好的,一次一个问题。
这是一个简单的套接字服务器框架:
s_sock = socket.socket()
s_sock.bind()
s_sock.listen()
while True:
c_sock, c_addr = s_sock.accept()
process_client_sock(c_sock, c_addr)
服务器将循环并接受来自客户端的连接,然后调用其进程函数与客户端套接字进行通信。这里有一个问题: process_client_sock
可能需要很长时间,甚至包含一个循环(通常就是这种情况)。
def process_client_sock(c_sock, c_addr):
while True:
receive_or_send_data(c_sock)
在这种情况下,服务器无法再接受任何连接。
一个简单的解决方案是使用多进程或多线程,只需创建一个新线程来处理请求,而主循环继续监听新连接。
s_sock = socket.socket()
s_sock.bind()
s_sock.listen()
while True:
c_sock, c_addr = s_sock.accept()
thread = Thread(target=process_client_sock, args=(c_sock, c_addr))
thread.start()
这当然有效,但考虑到性能还不够好。因为新的进程/线程占用额外的CPU和内存,所以服务器不空闲可能会获得数千个连接。
因此,select
和poll
系统调用会尝试解决此问题。您给select
一组文件描述符,并告诉它是否有任何fd准备好读/写/或发生异常。
是或否取决于您传递给它的参数。
正如select man page所说,它将获得struct timeval
参数
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
有三种情况:
timeout.tv_sec == 0和timeout.tv_usec = 0
无阻塞,立即返回
超时== NULL
永远阻止,直到文件描述符准备就绪。
超时是正常的
等待一段时间,如果仍然没有可用的文件描述符,则超时并返回。
用简单的话说:轮询在等待IO 时释放CPU用于其他工作。
这是基于
的简单事实希望它有所帮助。
答案 1 :(得分:9)
如果您执行read
或recv
,则只能等待一个连接。如果您有多个连接,则必须创建多个进程或线程,这会浪费系统资源。
使用select
或poll
或epoll
,您可以仅使用一个线程监控多个连接,并在其中任何一个数据可用时收到通知,然后您调用{{1相应连接上的{}或read
。
它可以无限制地阻塞,阻止给定时间,或者根本不阻塞,具体取决于参数。
答案 2 :(得分:2)
select()接受3个套接字列表来检查三个条件(读,写,错误),然后返回(实际上更短,通常是空的)套接字列表,这些套接字实际上已准备好为这些条件处理。
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.bind((Local_IP, Port1))
s1.listen(5)
s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2.bind((Local_IP, Port2))
s2.listen(5)
sockets_that_might_be_ready_to_read = [s1,s2]
sockets_that_might_be_ready_to_write_to = [s1,s2]
sockets_that_might_have_errors = [s1,s2]
([ready_to_read], [ready_to_write], [has_errors]) =
select.select([sockets_that_might_be_ready_to_read],
[sockets_that_might_be_ready_to_write_to],
[sockets_that_might_have_errors], timeout)
for sock in ready_to_read:
c,a = sock.accept()
data = sock.recv(128)
...
for sock in ready_to_write:
#process writes
...
for sock in has_errors:
#process errors
因此,如果套接字在等待超时秒之后没有尝试连接,则列表ready_to_read将为空 - 此时,如果accept()和recv()阻塞则无关紧要 - 它们将不会被调用对于空列表....
如果套接字已准备好读取,那么如果有数据,那么它也不会阻塞。