eventlet과 gevent 사이의 성능에 중요한 차이를 만드는 것은 무엇입니까?
-
12-12-2019 - |
문제
결과적으로 두 라이브러리는 유사한 철학과 유사한 디자인 결정을 공유합니다.하지만 이 인기 있는 WSGI 벤치마크 라고 eventlet
것보다 훨씬 느립니다 gevent
.무엇이 그들의 성과를 그토록 다르게 만드는가?
내가 알고 있듯이 이들 사이의 주요 차이점은 다음과 같습니다.
gevent
의도적으로 의존하고 결합됩니다.libev
(libevent
, 이전) 동안eventlet
독립적인 반응기 인터페이스를 정의하고 다음을 사용하여 특정 어댑터를 구현합니다.select
,epoll
, 그리고 그 뒤에는 뒤틀린 반응기가 있습니다. 추가 반응기 인터페이스로 인해 심각한 성능 저하가 발생합니까?gevent
대부분 Cython으로 작성되었지만eventlet
순수 Python으로 작성되었습니다. 계산량이 많지 않지만 IO 바인딩된 프로그램의 경우 기본적으로 컴파일된 Cython이 순수 Python보다 훨씬 더 빠른가요?의 기본
gevent
표준 라이브러리의 인터페이스를 에뮬레이트하는 동시에eventlet
의 프리미티브는 표준과 다르며 이를 에뮬레이션하기 위한 추가 레이어를 제공합니다. 추가 에뮬레이션 계층이eventlet
더 천천히?구현인가?
eventlet.wsgi
그냥 더 나쁜 것보다gevent.pywsgi
?
정말 궁금합니다. 왜냐하면 그것들이 나에게는 전반적으로 너무 비슷해 보이기 때문입니다.
해결책
글쎄, gevent는 Cython으로 "대부분" 작성되지 않았지만 일부 중요한 섹션은 작성되었습니다.
Cython은 큰 차이를 만듭니다.프로세서 최적화는 컴파일된 코드에서 훨씬 더 잘 작동합니다.예를 들어 분기 예측은 VM 실행 수준에서 분기의 간접적인 방향이 불투명하기 때문에 VM 기반 시스템에서는 무너집니다.캐시 공간이 더 촘촘해졌습니다.컴파일된 코드는 여기서 큰 차이를 만들어내며 IO는 대기 시간에 매우 민감할 수 있습니다.
비슷한 맥락에서 libev는 매우 빠릅니다.같은 이유.
Eventlet이 선택 허브를 사용해야 했던 것 같지는 않습니다(Python 2.6은 일반적으로 epoll을 기본값으로 설정합니다).그래도 선택에 멈췄다면 그렇게 될 것입니다. 정말 느립니다(Python은 select fd_set를 Python 목록으로 앞뒤로 변환해야 하기 때문에 루프 중간에 있으면 보기 흉해집니다).
나는 어떤 프로파일링도 하지 않았지만 libev/libevent와 Cython이 큰 차이를 만든다고 확신합니다.특히 일부 스레딩 기본 요소는 Cython의 gevent에 있습니다.많은 코드가 IO와 일부 지점의 표준 라이브러리를 통해 간접적으로 접촉하기 때문에 이는 큰 문제입니다.
Eventlet의 추가 에뮬레이션 레이어에 관해서는 훨씬 더 탄력적인 것으로 보입니다.gevent에서 코드 경로는 콜백을 구성하고 허브가 이를 호출하도록 하는 것으로 보입니다.eventlet은 허브가 gevent에서 수행하는 장부 관리 작업을 더 많이 수행하는 것으로 보입니다.하지만 다시 한 번 말씀드리지만 프로필을 작성하지 않았습니다.몽키패칭 자체는 상당히 비슷해 보입니다.
WSGI 서버는 또 다른 어려운 서버입니다.특히, gevent의 헤더 구문 분석은 표준 라이브러리로 연기되는 반면, gevent에서는 이를 자체적으로 구현합니다.이것이 큰 영향인지 아닌지는 확실하지 않지만 거기에 뭔가가 숨어 있다면 놀랄 일이 아닙니다.가장 눈에 띄는 점은 eventlet의 서버가 표준 라이브러리 BaseHTTPServer의 원숭이 패치 버전을 기반으로 한다는 것입니다.나는 이것이 매우 최적이라고 상상할 수 없습니다.Gevent는 에뮬레이션을 인식하는 서버를 구현합니다.
다른 팁
늦은 답변 죄송합니다.
성능 차이가 큰 두 가지 주요 이유가 있습니다. 해당 벤치마크에서:
- 앞서 언급했듯이 gevent의 주요 경로는 크게 최적화되어 있습니다.
- 해당 벤치마크는 스트레스 테스트를 수행합니다.머신이 가능한 한 많은 요청을 실행하도록 시도하기 때문에 더 이상 IO 바인딩이 아닙니다.이것이 Cythonized 코드가 빛나는 곳입니다.
"실제 세계에서"는 "슬래시닷" 트래픽 폭주 중에만 발생합니다.어느 것이 중요하고 준비가 되어 있어야 하지만, 그런 일이 발생하면 더 많은 서버를 추가하거나 리소스를 많이 사용하는 기능을 비활성화하여 대응합니다.부하가 증가하면 실제로 더 많은 서버를 추가하는 벤치마크를 본 적이 없습니다.
반면에 벤치마크가 "평상시" 로드(웹 사이트마다 다름)를 시뮬레이션하지만 일반적으로 요청, 임의 일시 중지, 반복으로 근사할 수 있는 경우입니다.일시 중지가 적을수록 시뮬레이션하는 트래픽이 많아집니다.또한 벤치마크의 클라이언트 측에서는 대기 시간을 시뮬레이션해야 합니다.Linux에서는 멋진 netem[1]을 사용하여 이 작업을 수행할 수 있습니다. 그렇지 않으면 수신/전송 호출 전에 약간의 지연을 두어 수행할 수 있습니다(벤치마크는 일반적으로 더 높은 수준의 라이브러리를 사용하기 때문에 매우 어려울 수 있습니다).
이제 이러한 조건이 충족되면 실제로 IO 바운드 문제를 벤치마킹합니다.그러나 결과는 그다지 좋지 않을 것입니다.모든 후보자는 10, 50, 심지어 200qps 로드를 성공적으로 처리했습니다.지루하지 않나요?따라서 지연 시간 분포, 99% 요청을 처리하는 데 걸리는 시간 등을 측정할 수 있습니다.Gevent는 여전히 더 나은 결과를 보여줄 것입니다.그러나 그 차이는 거의 인상적이지 않을 것입니다.