Pergunta

Essas duas bibliotecas compartilham uma filosofia semelhante e, como resultado, decisões de design semelhantes.Mas este popular benchmark WSGI diz eventlet é muito mais lento do que gevent.O que torna seu desempenho tão diferente?

Como sei, as principais diferenças entre eles são:

  • gevent intencionalmente depende e está acoplado a libev (libevent, anteriormente) enquanto eventlet define interface de reator independente e implementa adaptadores específicos usando select, epoll, e o reator Twisted atrás dele. A interface adicional do reator causa impactos críticos no desempenho?

  • gevent é escrito principalmente em Cython enquanto eventlet é escrito em Python puro. O Cython compilado nativamente é tão mais rápido que o Python puro, para programas não tão computacionais, mas vinculados a IO?

  • Primitivos de gevent emular interfaces de bibliotecas padrão enquanto eventletAs primitivas do s diferem do padrão e fornecem uma camada adicional para emulá-lo. A camada de emulação adicional torna eventlet Mais devagar?

  • É a implementação de eventlet.wsgi apenas pior do que gevent.pywsgi?

Eu realmente me pergunto, porque no geral eles parecem muito semelhantes para mim.

Foi útil?

Solução

Bem, gevent não é "principalmente" escrito em Cython, embora algumas seções críticas sejam.

Cython faz uma enorme diferença.As otimizações do processador funcionam muito melhor com código compilado.A previsão de ramificação, por exemplo, falha em sistemas baseados em VM porque a indireção da ramificação no nível de execução da VM é opaca para ela.A área ocupada pelo cache é menor.O código compilado faz uma grande diferença aqui, e o IO pode ser muito sensível à latência.

Na mesma linha, libev é muito rápido.Mesmas razões.

Não parece que o eventlet deveria estar usando o hub de seleção (o Python 2.6 geralmente usa como padrão o epoll).Se estivesse preso no select, isso faria com que realmente lento (porque o Python precisa converter o select fd_set para frente e para trás em uma lista do Python, então fica feio quando está no meio de um loop).

Não fiz nenhum perfil, mas aposto que libev/libevent mais Cython fazem uma grande diferença.Notavelmente, algumas das primitivas de threading estão no Cython em gevent.Isso é importante porque muito código os atinge indiretamente por meio de IO e até mesmo da biblioteca padrão em alguns pontos.

Quanto à camada adicional de emulação do eventlet, parece haver muito mais elasticidade.No gevent, o caminho do código parece construir retornos de chamada e permitir que o hub os chame.eventlet parece fazer mais contabilidade do que o hub está fazendo em gevent.Novamente, porém, eu não fiz um perfil dele.Quanto ao monkeypatching em si, eles são bastante semelhantes.

O servidor WSGI é outro difícil.Notavelmente, a análise do cabeçalho no gevent é adiada para a biblioteca padrão, enquanto eles próprios a implementam no eventlet.Não tenho certeza se isso é um grande impacto ou não, mas não seria surpresa se houvesse algo escondido ali.O mais revelador é que o servidor do eventlet é baseado em uma versão com patch de macaco da biblioteca padrão BaseHTTPServer.Não consigo imaginar que isso seja ideal.Gevent implementa um servidor que reconhece a emulação.

Outras dicas

Desculpe pela resposta tardia.

Existem duas razões principais para a grande diferença de desempenho naquela referência:

  • como afirmado antes, os caminhos críticos do gevent são fortemente otimizados
  • esse benchmark faz testes de estresse.Não está mais vinculado ao IO, porque tenta fazer com que a máquina execute o maior número possível de solicitações.E é aí que o código Cythonized brilha.

"No mundo real", isso só acontece durante picos de tráfego "slashdot".O que é importante e deve-se estar pronto, mas quando isso acontece, você reage adicionando mais servidores ou desativando recursos com muitos recursos.Não vi um benchmark que realmente adicione mais servidores quando a carga aumenta.

Se, por outro lado, o benchmark simulasse uma carga de “dia normal” (que variaria de um site para outro), mas geralmente poderia ser aproximado para solicitação, pausa aleatória, repetição.Quanto menos pausa, mais tráfego simulamos.Além disso, o lado do cliente do benchmark teria que simular a latência.No Linux isso poderia ser feito usando o incrível netem[1], caso contrário, colocando pequenos atrasos antes das chamadas recv/send (o que seria muito difícil porque os benchmarks geralmente usam bibliotecas de nível superior).

Agora, se essas condições forem atendidas, na verdade compararíamos problemas vinculados a IO.Mas os resultados não seriam tão impressionantes:todos os candidatos atenderam com êxito cargas de 10, 50 e até 200 qps.Chato, certo?Assim, poderíamos medir a distribuição de latência, tempo para atender 99% das solicitações, etc.Gevent ainda apresentaria melhores resultados.Mas a diferença dificilmente seria impressionante.

[1] Simule pacotes atrasados ​​e descartados no Linux

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top