Python 비동기 IO 구현 예시

4898 단어 python비동기io
머리말
블록 API 로 동기 화 코드 를 쓰 는 것 이 가장 간단 하지만 하나의 스 레 드 는 같은 시간 에 하나의 요청 만 처리 할 수 있 습 니 다.제 한 된 스 레 드 수 로 인해 만 단계 의 병렬 연결 을 실현 하지 못 하고 너무 많은 스 레 드 전환 도 CPU 의 시간 을 빼 앗 아 초당 처리 할 수 있 는 요청 수량 을 낮 출 수 있 습 니 다.높 은 병발 을 위해 비동기 프레임 워 크 를 선택 할 수 있 습 니 다.비 차단 API 로 업무 논 리 를 여러 개의 반전 함수 로 흐 트 러 뜨리 고 다 중 재 활용 과 이벤트 순환 방식 으로 높 은 병발 을 실현 할 수 있 습 니 다.
디스크 IO 의 경우 다 중 스 레 드 에서 차단 방법 으로 디스크 를 읽 고 2 개의 스 레 드 간 전환 방식 을 설명 합 니 다.그렇다면 어떻게 해야만 높 은 병발 을 실현 할 수 있 을 까?

위의 그림 에서 커 널 에서 실 현 된 요청 전환 작업 을 사용자 상태의 코드 에 맡 기 면 됩 니 다.비동기 화 프로 그래 밍 은 응용 층 코드 를 통 해 요청 전환 을 실현 하고 전환 원가 와 메모리 점용 공간 을 낮 춥 니 다.비동기 화 는 IO 다 중 재 활용 체제 에 의존 합 니 다.예 를 들 어 Linux 의 epoll 이나 Windows 의 iocp 등 이 있 습 니 다.또한 차단 방법 을 비 차단 방법 으로 바 꿔 야 커 널 전환 에 따 른 큰 소 모 를 피 할 수 있 습 니 다.Nginx,Redis 등 고성능 서 비 스 는 모두 비동기 화 에 의존 해 백만 급 의 병발 을 이 루 었 다.
다음 그림 은 비동기 IO 의 비 차단 읽 기와 비동기 프레임 워 크 가 결 합 된 후 요청 을 어떻게 전환 하 는 지 설명 한다.

그러나 비동기 화 코드 를 쓰 는 것 은 오류 가 발생 하기 쉽다.모든 차단 함 수 는 차단 되 지 않 은 시스템 호출 을 통 해 두 함수 로 나 누 어야 하기 때문이다.이 두 함수 가 공동으로 하나의 기능 을 완성 하지만 호출 방식 은 다르다.첫 번 째 함 수 는 당신 이 명시 적 으로 호출 하고 두 번 째 함 수 는 다 중 재 활용 체제 에서 호출 합 니 다.
이런 방식 은 소프트웨어 공학 의 내부 집적 원칙 을 위반 하고 함수 간 동기 데이터 도 더욱 복잡 하 다.특히 조건 이 많 고 대량의 시스템 호출 과 관련 될 때 비동기 화 된 개조 작업 은 매우 어 려 울 것 이다.
Python 은 어떻게 비동기 호출 을 실현 합 니까?

from flask import Flask
import time
app = Flask(__name__)


@app.route('/bar')
def bar():
  time.sleep(1)
  return '<h1>bar!</h1>'

@app.route('/foo')
def foo():
  time.sleep(1)
  return '<h1>foo!</h1>'
if __name__ == '__main__':
  app.run(host='127.0.0.1',port=5555,debug=True)
동기 화 방식 으로 호출 하 다

import requests
import time

starttime = time.time()
print(requests.get('http://127.0.0.1:5555/bar').content)
print(requests.get('http://127.0.0.1:5555/foo').content)
print("    : ",time.time() -starttime)
b'

bar!

'
b'

foo!

'
소모 시간:  2.015509605407715
샘플링 비동기 방식 호출:
중점:
1.차단 io 를 비 차단 io 로 변경 합 니 다.
2.다 중 재 활용 io 커 널 이벤트 감청,이벤트 트리거 는 리 셋 함 수 를 통 해 발생 합 니 다.
3.사용자 상태 코드 는 이벤트 순환 방식 으로 이 벤트 를 가 져 오고 이벤트 의 리 셋 함 수 를 실행 합 니 다.

import selectors
import socket
import time
# from asynrequest import ParserHttp
class asynhttp:
  def __init__(self):
    self.selecter = selectors.DefaultSelector()

  def get(self,url,optiondict = None):
    global reqcount
    reqcount += 1
    s = socket.socket()
    s.setblocking(False)
    try:
      s.connect(('127.0.0.1',5555))
    except BlockingIOError:
      pass
    requset = 'GET %s HTTP/1.0\r
\r
' % url callback = lambda : self.send(s,requset) self.selecter.register(s.fileno(),selectors.EVENT_WRITE,callback) def send(self,s,requset): self.selecter.unregister(s.fileno()) s.send(requset.encode()) chunks = [] callback = lambda: self.recv(s,chunks) self.selecter.register(s.fileno(),selectors.EVENT_READ,callback) def recv(self,s,chunks): self.selecter.unregister(s.fileno()) chunk = s.recv(1024) if chunk: chunks.append(chunk) callback = lambda: self.recv(s,chunks) self.selecter.register(s.fileno(), selectors.EVENT_READ, callback) else: global reqcount reqcount -= 1 request_first,request_headers,request_content,_ = ParserHttp.parser(b''.join(chunks)) print(" :",request_first,request_headers,request_content) print((b''.join(chunks)).decode()) return (b''.join(chunks)).decode() starttime = time.time() reqcount = 0 asynhttper = asynhttp() asynhttper.get('/bar') asynhttper.get('/foo') while reqcount: events = asynhttper.selecter.select() for event,mask in events: func = event.data func() print(" :" ,time.time() - starttime)
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 13
Server: Werkzeug/1.0.1 Python/3.7.7
Date: Thu, 15 Oct 2020 03:28:16 GMT

bar!


HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 13
Server: Werkzeug/1.0.1 Python/3.7.7
Date: Thu, 15 Oct 2020 03:28:16 GMT

foo!


소모 시간:1.012763738632121
이상 은 Python 이 비동기 IO 를 실현 하 는 예제 의 상세 한 내용 입 니 다.python 비동기 IO 에 관 한 자 료 는 다른 관련 글 에 주목 하 십시오!

좋은 웹페이지 즐겨찾기