我的python学习笔记之select模块

本文介绍了Python中的select模块,详细阐述了select方法的工作原理及其实现并发服务端的示例。同时,对比分析了epoll方法的优势,包括减少文件描述符复制和使用回调函数提高效率,并解释了水平触发与边缘触发的区别。文章最后通过实例展示了epoll在服务端的应用。
摘要由CSDN通过智能技术生成

简介

Python中的select模块专注于I/O多路复用,提供了select poll epoll三个方法(其中后两个在Linux中可用,windows仅支持select),另外也提供了kqueue方法(freeBSD系统)

博文说明:
1,本文中的代码都已运行成功;
2,所有截图都是博主自己截取的,写一篇完整的博客确实很辛苦,整理素材输出文档;
3,如果转载,请注明出处。

运行环境说明:
	OS发行版:CentOS7.4
	python版本:
		【epoll实例服务端1】使用python3.6和python2.7.5
		【epoll实例服务端2】使用python2.7.5
		【所有客户端】使用python2.7.5

select方法

进程指定内核监听哪些文件描述符(最多监听1024个fd)的哪些事件,当没有文件描述符事件发生时,进程被阻塞;当一个或者多个文件描述符事件发生时,进程被唤醒。

当我们调用select()时:

  1. 上下文切换转换为内核态
  2. 将fd从用户空间复制到内核空间
  3. 内核遍历所有fd,查看其对应事件是否发生
  4. 如果没发生,将进程阻塞,当设备驱动产生中断或者timeout时间后,将进程唤醒,再次进行遍历
  5. 返回遍历后的fd
  6. 将fd从内核空间复制到用户空间

fd:file descriptor 文件描述符

fd_r_list, fd_w_list, fd_e_list = select.select(rlist, wlist, xlist, [timeout])

参数: 可接受四个参数(前三个必须)

  • rlist: wait until ready for reading
  • wlist: wait until ready for writing
  • xlist: wait for an “exceptional condition”
  • timeout: 超时时间

返回值:三个列表

select方法用来监视文件描述符(当文件描述符条件不满足时,select会阻塞),当某个文件描述符状态改变后,会返回三个列表

  • 当参数1 序列中的fd满足“可读”条件时,则获取发生变化的fd并添加到fd_r_list中
  • 当参数2 序列中含有fd时,则将该序列中所有的fd添加到 fd_w_list中
  • 当参数3 序列中的fd发生错误时,则将该发生错误的fd添加到 fd_e_list中
  • 当超时时间为空,则select会一直阻塞,直到监听的句柄发生变化,当超时时间 = n(正整数)时,那么如果监听的句柄均无任何变化,则select会阻塞n秒,之后返回三个空列表,如果监听的句柄有变化,则直接执行。

select实例:利用select实现一个可并发的服务端

服务端:

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import socket
import select

ip_port = ("192.168.12.172", 9999)
sk1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sk1.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sk1.bind(ip_port)
sk1.listen(5)
sk1.setblocking(0)

inputs = [sk1,]

print "inputs: ", inputs
while True:
    #要不断的调用select函数来检查给定的类文件对象是否有数据就绪,当且仅当有新客户端连接进来的时候,sk1服务端这个套接字对象才是读就绪的,也就是才会存在于readable_list列表中;
    readable_list, writeable_list, error_list = select.select(inputs, [], inputs, 1)
    print "readable_list: ", readable_list
    for r in readable_list:
        #当客户端第一次连接服务端时,sk1服务端套接字对象,通过调用accept方法获取到新进来的客户端套接字,然后把新进来的客户端套接字对象追加到,待select检测的inputs列表中。
        if sk1 == r:
            print "r=sk1: ", r
            print "first accept"
            request, address = r.accept()
            request.setblocking(0)
            inputs.append(request)
            print "first inputs: ", inputs
        #当客户端连接上服务器端之后,再次发送数据时
        else:
            print "myr: ", r
            received = r.recv(1024)
            print "received: ", received
            #当正常接收客户端发送的数据时
            if received:
                print "received data: ", received
            #当客户端关闭程序时
            else:
                inputs.remove(r)
sk1.close()

客户端:

#!/usr/bin/env python
#-*- coding: utf-8 -*-

import socket

ip_port = ("192.168.12.172", 9999)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(ip_port)

while True:
    inp = raw_input("Please enter:")
    client.sendall(inp)
client.close()

在服务端我们可以看到,我们需要不停的调用select, 这就意味着:

  • 当文件描述符过多时,文件描述符在用户空间与内核空间进行copy会很费时
  • 当文件描述符过多时,内核对文件描述符的遍历也很浪费时间
  • select最大仅仅支持1024个文件描述符

poll与select相差不大,本文不作介绍

  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值