python 의 select 모듈 을 깊이 이해 합 니 다.

7532 단어 pythonselect 모듈
간단 한 소개
Python 의 select 모듈 은 I/O 다 중 재 활용 에 전념 하여 select 를 제공 합 니 다.  poll  epoll 세 가지 방법(그 중 두 가 지 는 Linux 에서 사용 할 수 있 고 windows 는 select 만 지원 합 니 다),또한 kquue 방법(freeBSD 시스템)도 제공 합 니 다.
select 방법
프로 세 스 는 커 널 이 어떤 파일 설명자(최대 1024 개 fd 감청)를 감청 하 는 지 지정 합 니 다.파일 설명자 사건 이 발생 하지 않 았 을 때 프로 세 스 가 막 혔 습 니 다.하나 이상 의 파일 설명자 이벤트 가 발생 했 을 때 프로 세 스 가 깨 어 났 습 니 다.
우리 가 select()를 호출 할 때:
1.문맥 이 커 널 상태 로 전환
2.fd 를 사용자 공간 에서 커 널 공간 으로 복사 합 니 다.
3.커 널 은 모든 fd 를 옮 겨 다 니 며 해당 이벤트 가 발생 했 는 지 확인 합 니 다.
4.발생 하지 않 으 면 프로 세 스 를 막 습 니 다.장치 구동 이 중단 되 거나 timeout 시간 이 발생 하면 프로 세 스 를 깨 우 고 다시 옮 겨 다 닙 니 다.
5.옮 겨 다 니 는 fd 를 되 돌려 줍 니 다.
6.fd 를 커 널 공간 에서 사용자 공간 으로 복사 합 니 다.
fd:파일 기술자 파일 설명자

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.매개 변수 1 시퀀스 의 fd 가'읽 기 가능'조건 을 만족 시 킬 때 변화 하 는 fd 를 가 져 와 fd 에 추가 합 니 다.r_목록
        2.매개 변수 2 시퀀스 에 fd 가 포함 되 어 있 을 때 이 시퀀스 의 모든 fd 를 fd 에 추가 합 니 다.w_목록
        3.매개 변수 3 시퀀스 의 fd 에 오류 가 발생 하면 이 오류 가 발생 한 fd 를 fd 에 추가 합 니 다.e_목록
        4.시간 초과 시간 이 비어 있 으 면 select 는 감청 의 핸들 이 변 할 때 까지 계속 차단 합 니 다.
       시간 초과=n(정수)일 때 감청 핸들 이 변 하지 않 으 면 selection 은 n 초 를 막 고 세 개의 빈 목록 으로 돌아 가 감청 핸들 이 변 하면 바로 실 행 됩 니 다.
    인 스 턴 스:select 를 이용 하여 동시 다발 가능 한 서버 를 실현 합 니 다.
    
    import socket
    import select
    
    s = socket.socket()
    s.bind(('127.0.0.1',8888))
    s.listen(5)
    r_list = [s,]
    num = 0
    while True:
     rl, wl, error = select.select(r_list,[],[],10)
     num+=1
     print('counts is %s'%num)
     print("rl's length is %s"%len(rl))
     for fd in rl:
      if fd == s:
       conn, addr = fd.accept()
       r_list.append(conn)
       msg = conn.recv(200)
       conn.sendall(('first----%s'%conn.fileno()).encode())
      else:
       try:
        msg = fd.recv(200)
        fd.sendall('second'.encode())
       except ConnectionAbortedError:
        r_list.remove(fd)
    
    
    s.close()
    
    import socket
    
    flag = 1
    s = socket.socket()
    s.connect(('127.0.0.1',8888))
    while flag:
     input_msg = input('input>>>')
     if input_msg == '0':
      break
     s.sendall(input_msg.encode())
     msg = s.recv(1024)
     print(msg.decode())
    
    s.close()
    서버 에서 우 리 는 select 를 끊임없이 호출 해 야 한 다 는 것 을 알 수 있 습 니 다.이것 은 다음 과 같 습 니 다.
      1  파일 설명자 가 너무 많 을 때 파일 설명자 가 사용자 공간 과 커 널 공간 에서 copy 를 하 는 데 시간 이 많이 걸 립 니 다.
      2  파일 설명자 가 너무 많 을 때 커 널 이 파일 설명자 에 대한 옮 겨 다 니 는 것 도 시간 을 낭비 합 니 다.
      3  select 최대 1024 개의 파일 설명자 만 지원 합 니 다.
    poll 과 select 의 차이 가 크 지 않 으 므 로 본 고 는 소개 하지 않 습 니 다.
    epoll 방법:
    epoll 은 select 를 잘 개선 했다.
    1.epoll 의 해결 방안 은 epoll 에 있 습 니 다.ctl 함수 중.epoll 핸들 에 새로운 이 벤트 를 등록 할 때마다 epoll 이 아 닌 모든 fd 를 커 널 에 복사 합 니 다.wait 때 복사 반복.epoll 은 모든 fd 가 전체 과정 에서 한 번 만 복사 할 수 있 도록 보장 합 니 다.
    2,epoll 은 epollctl 시 지정 한 fd 를 한 번 옮 겨 다 니 며(이번 에는 없어 서 는 안 됩 니 다)모든 fd 에 리 셋 함 수 를 지정 합 니 다.장치 가 준비 되 어 대기 열 에 있 는 대기 자 를 깨 울 때 이 리 셋 함 수 를 호출 합 니 다.이 리 셋 함 수 는 준 비 된 fd 를 준비 링크 에 추가 합 니 다.epoll_wait 작업 은 실제로 이 준비 링크 에서 준비 되 어 있 는 fd 를 확인 하 는 것 입 니 다.
    3.epoll 은 파일 설명자 에 대해 추가 제한 이 없습니다.
    
    select.epoll(sizehint=-1, flags=0)   epoll  
    
    
    epoll.close()
    Close the control file descriptor of the epoll object.  epoll        
    
    epoll.closed
    True if the epoll object is closed.  epoll      
    
    epoll.fileno()
    Return the file descriptor number of the control fd.  epoll        
    
    epoll.fromfd(fd)
    Create an epoll object from a given file descriptor.     fd  epoll  
    
    epoll.register(fd[, eventmask])
    Register a fd descriptor with the epoll object. epoll     fd      
    
    epoll.modify(fd, eventmask)
    Modify a registered file descriptor.  fd   
    
    epoll.unregister(fd)
    Remove a registered file descriptor from the epoll object.    
    
    epoll.poll(timeout=-1, maxevents=-1)
    Wait for events. timeout in seconds (float)  ,     fd    ,     dict,   :{(fd1,event1),(fd2,event2),……(fdn,eventn)}
    이벤트:
    
    EPOLLIN Available for read        1
    EPOLLOUT Available for write        4
    EPOLLPRI Urgent data for read
    EPOLLERR Error condition happened on the assoc. fd          8
    EPOLLHUP Hang up happened on the assoc. fd     
    EPOLLET Set Edge Trigger behavior, the default is Level Trigger behavior        ,           
    EPOLLONESHOT Set one-shot behavior. After one event is pulled out, the fd is internally disabled
    EPOLLRDNORM Equivalent to EPOLLIN
    EPOLLRDBAND Priority data band can be read.
    EPOLLWRNORM Equivalent to EPOLLOUT
    EPOLLWRBAND Priority data may be written.
    EPOLLMSG Ignored.
    수평 트리거 와 가장자리 트리거:
    Level_triggered(수평 트리거,조건 트리거 라 고도 함):감 시 된 파일 설명자 에 읽 기와 쓰기 이벤트 가 발생 했 을 때epoll.poll()처리 프로그램 에 읽 기와 쓰 기 를 알 립 니 다.만약 이번에 데 이 터 를 한꺼번에 다 읽 고 쓰 지 않 았 다 면(예 를 들 어 읽 기 쓰기 버퍼 가 너무 작 았 다 면)다음 호출epoll.poll()에 서 는 다 읽 지 못 한 파일 설명자 에서 계속 읽 고 쓰 라 고 알려 줄 것 입 니 다.물론 읽 고 쓰 지 않 으 면 계속 알려 줄 것 입 니 다!!만약 시스템 에 읽 고 쓸 필요 가 없 는 준 비 된 파일 설명자 가 대량으로 있다 면,그들 은 매번 돌아 올 것 입 니 다.그러면 처리 프로그램 이 자신 이 관심 을 가 지 는 준 비 된 파일 설명 자 를 검색 하 는 효율 을 크게 낮 출 것 입 니 다!!장점 뚜렷:안정 적 이 고 신뢰 할 수 있다.
    Edge_triggered(가장자리 트리거,상태 트리거 라 고도 함):감 시 된 파일 설명자 에 읽 기와 쓰기 이벤트 가 발생 했 을 때epoll.poll()처리 프로그램 에 읽 기와 쓰 기 를 알 립 니 다.만약 이번에 데 이 터 를 전부 읽 고 쓰 지 않 았 다 면(예 를 들 어 읽 기 쓰기 버퍼 가 너무 작 았 다 면)다음 호출epoll.poll()시 알려 주지 않 을 것 입 니 다.즉,이 파일 설명자 에 두 번 째 읽 기 쓰기 이벤트 가 나타 날 때 까지 한 번 만 알려 줄 것 입 니 다!!이러한 모델 은 수평 트리거 효율 보다 높 습 니 다.시스템 은 당신 이 관심 이 없 는 준비 파일 설명자 로 가득 하지 않 습 니 다!!단점:어떤 조건 에 서 는 믿 을 수 없다.
    epoll 실례:
    
    import socket
    import select
    
    s = socket.socket()
    s.bind(('127.0.0.1',8888))
    s.listen(5)
    epoll_obj = select.epoll()
    epoll_obj.register(s,select.EPOLLIN)
    connections = {}
    while True:
     events = epoll_obj.poll()
     for fd, event in events:
      print(fd,event)
      if fd == s.fileno():
       conn, addr = s.accept()
       connections[conn.fileno()] = conn
       epoll_obj.register(conn,select.EPOLLIN)
       msg = conn.recv(200)
       conn.sendall('ok'.encode())
      else:
       try:
        fd_obj = connections[fd]
        msg = fd_obj.recv(200)
        fd_obj.sendall('ok'.encode())
       except BrokenPipeError:
        epoll_obj.unregister(fd)
        connections[fd].close()
        del connections[fd]
    
    s.close()
    epoll_obj.close()
    
    import socket
    
    flag = 1
    s = socket.socket()
    s.connect(('127.0.0.1',8888))
    while flag:
     input_msg = input('input>>>')
     if input_msg == '0':
      break
     s.sendall(input_msg.encode())
     msg = s.recv(1024)
     print(msg.decode())
    
    s.close()
    총결산
    이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

    좋은 웹페이지 즐겨찾기