Há muito tempo atrás, escrevi uma teia de aranha que multithread para permitir que solicitações simultâneas ocorressem ao mesmo tempo. Isso foi na minha juventude em Python, nos dias antes de eu conhecer o GIL e os problemas associados que ele cria para o código multithread (IE, na maioria das vezes, as coisas acabam sendo serializadas!) ...
Gostaria de refazer esse código para torná-lo mais robusto e com melhor desempenho. Existem basicamente duas maneiras de fazer isso: eu poderia usar o novo módulo de multiprocessamento no 2.6+ ou eu poderia usar algum modelo baseado em reator / evento. Prefiro fazer o mais tarde, pois é muito mais simples e menos propenso a erros.
Portanto, a pergunta se refere a qual estrutura seria mais adequada às minhas necessidades. A seguir, é apresentada uma lista das opções que eu conheço até agora:
- Twisted : O avô das estruturas dos reatores Python: parece complexo e um pouco inchado. Curva de aprendizado acentuada para uma pequena tarefa.
- Eventlet : Dos caras do lindenlab . Estrutura baseada em greenlet voltada para esse tipo de tarefa. No entanto, dei uma olhada no código e não é muito bonito: não compatível com o pep8, repleto de impressões (por que as pessoas fazem isso em uma estrutura !?), a API parece um pouco inconsistente.
- PyEv : Imaturo, parece não haver ninguém usando agora, embora seja baseado no libevent, por isso possui um back-end sólido.
- asyncore : A partir do stdlib: über de baixo nível, parece ser muito trabalho braçal apenas para tirar algo do chão.
- tornado : Embora seja um produto orientado ao servidor, projetado para servidores de sites dinâmicos, ele possui um cliente HTTP assíncrono e um ioloop simples . Parece que poderia fazer o trabalho, mas não para o que se destinava. [editar: infelizmente, não roda no Windows, o que é importante para mim - é um requisito para eu apoiar esta plataforma fraca]
Há algo que eu perdi? Certamente deve haver uma biblioteca por aí que se encaixe no ponto ideal de uma biblioteca de rede assíncrona simplificada!
[editar: grandes agradecimentos a intgr por seu ponteiro para esta página . Se você rolar até o final, verá uma lista muito boa de projetos que visam realizar essa tarefa de uma maneira ou de outra. Parece que as coisas realmente mudaram desde o início do Twisted: as pessoas agora parecem preferir uma solução baseada em rotina ao invés de uma solução tradicional orientada a reatores / retornos de chamada. Os benefícios dessa abordagem são um código mais claro e direto: eu certamente encontrei no passado, especialmente ao trabalhar com o boost.asioem C ++, esse código baseado em retorno de chamada pode levar a designs difíceis de seguir e relativamente obscuros para quem não é treinado. O uso de co-rotinas permite escrever um código que pareça um pouco mais síncrono. Acho que agora minha tarefa é descobrir qual dessas muitas bibliotecas eu gosto da aparência e experimentar! Ainda bem que perguntei agora ...]
[editar: talvez seja de interesse para quem seguiu ou tropeçou nessa questão ou se preocupa com esse tópico em qualquer sentido: eu encontrei uma excelente descrição do estado atual das ferramentas disponíveis para este trabalho]
select
para a multiplexação de E / S. Mas você deve conseguir obter um desempenho decente com o tornado-pyuv . 2. Agora existe assíncrono no Python 3.3+ e seu trollius de backport, que permite executar qualquer aplicativo Tornado em seu loop de eventos (o Twisted será suportado em breve).Respostas:
Gostei do módulo Python de concorrência , que depende de microtreads Stackless Python ou Greenlets para rosqueamento leve. Todas as E / S de rede de bloqueio são transparentemente assíncronas por meio de um único
libevent
loop, portanto devem ser quase tão eficientes quanto um servidor assíncrono real.Suponho que seja semelhante ao Eventlet dessa maneira.
A desvantagem é que sua API é bem diferente dos
sockets
/threading
módulos do Python ; você precisa reescrever um pouco do seu aplicativo (ou escrever uma camada de compatibilidade)Edit: Parece que também há cogen , que é semelhante, mas usa os geradores aprimorados do Python 2.5 para suas corotinas, em vez de Greenlets. Isso o torna mais portátil que a concorrência e outras alternativas. A E / S de rede é feita diretamente com epoll / kqueue / iocp.
fonte
Torcido é complexo, você está certo sobre isso. Torcido não está inchado.
Se você der uma olhada aqui: http://twistedmatrix.com/trac/browser/trunk/twisted, você encontrará um conjunto organizado, abrangente e muito bem testado de muitos protocolos da Internet, bem como código auxiliar para escrever e implantar aplicativos de rede muito sofisticados. Eu não confundiria inchaço com abrangência.
É sabido que a documentação do Twisted não é a mais fácil de usar à primeira vista, e acredito que isso afasta um número infeliz de pessoas. Mas Twisted é incrível (IMHO) se você colocar o tempo. Eu fiz e provou valer a pena, e eu recomendo a outras pessoas que tentem o mesmo.
fonte
gevent é limpo de eventos .
Em termos de API, ele segue as mesmas convenções da biblioteca padrão (em particular, módulos de encadeamento e multiprocessamento) onde faz sentido. Então você tem coisas familiares como Fila e Evento para trabalhar.
Ele suporta apenas o libevent ( update: libev desde 1.0 ) como implementação do reator, mas aproveita ao máximo, apresentando um servidor WSGI rápido baseado no libevent-http e resolvendo consultas DNS através do libevent-dns, em vez de usar um pool de threads como a maioria das outras bibliotecas Faz. ( atualização: já que 1.0 c-ares é usado para fazer consultas DNS assíncronas; o pool de threads também é uma opção.)
Como o eventlet, torna desnecessários os retornos de chamada e adiados usando greenlets .
Confira os exemplos: download simultâneo de vários URLs , webchat de pesquisas longas .
fonte
Uma comparação realmente interessante de tais estruturas foi compilada por Nicholas Piël em seu blog: vale a pena ler!
fonte
Nenhuma dessas soluções evitará o fato de o GIL impedir o paralelismo da CPU - elas são apenas maneiras melhores de obter o paralelismo de E / S que você já possui com os threads. Se você acha que pode fazer melhor IO, siga um destes procedimentos, mas se o seu gargalo estiver no processamento dos resultados, nada aqui ajudará, exceto o módulo de multiprocessamento.
fonte
Eu não chegaria ao ponto de chamar Twisted inchado, mas é difícil entender o que você pensa. Evitei realmente me envolver em um aprendizado por um bom tempo, pois sempre desejei algo um pouco mais fácil para 'pequenas tarefas'.
No entanto, agora que trabalhei um pouco mais, tenho que dizer que incluir todas as baterias é MUITO legal.
Todas as outras bibliotecas assíncronas com as quais trabalhei acabam sendo muito menos maduras do que parecem. O loop de eventos do Twisted é sólido.
Não sei ao certo como resolver a curva de aprendizado íngreme do Twisted. Pode ajudar se alguém o forçar e limpar algumas coisas, como remover todo o cruft de compatibilidade com versões anteriores e os projetos mortos. Mas essa é a natureza do software maduro, eu acho.
fonte
PortableGtkReactor
?Kamaelia ainda não foi mencionada. Seu modelo de simultaneidade baseia-se na conexão de componentes com a passagem de mensagens entre as caixas de entrada e as de saída. Aqui está uma breve visão geral.
fonte
Comecei a usar o twisted para algumas coisas. A beleza disso quase é porque está "inchado". Existem conectores para praticamente qualquer um dos principais protocolos existentes. Você pode ter um jabber bot que receberá comandos e será postado em um servidor irc, enviá-los por e-mail a alguém, executar um comando, ler em um servidor NNTP e monitorar uma página da Web em busca de alterações. A má notícia é que ele pode fazer tudo isso e tornar as coisas excessivamente complexas para tarefas simples, como o OP explicou. A vantagem do python é que você inclui apenas o que precisa. Portanto, enquanto o download pode ter 20 MB, você pode incluir apenas 2 MB de bibliotecas (o que ainda é muito). Minha maior reclamação com o twisted é que, embora incluam exemplos, qualquer coisa além de um servidor tcp básico você está por sua conta.
Embora não seja uma solução python, vi o node.js ganhar muito mais força ultimamente. Na verdade, eu considerei investigar projetos menores, mas me encolho quando ouço javascript :)
fonte
Há um bom livro sobre o assunto: "Twisted Network Programming Essentials", de Abe Fettig. Os exemplos mostram como escrever códigos muito pitonicos e, para mim, pessoalmente, não me parecem baseados em uma estrutura inchada. Veja as soluções do livro, se não estiverem limpas, não sei o que significa limpar.
Meu único enigma é o mesmo que tenho com outros frameworks, como Ruby. Eu me preocupo, isso aumenta? Detestaria comprometer um cliente com uma estrutura que apresentará problemas de escalabilidade.
fonte
O Whizzer é uma pequena estrutura de soquete assíncrona que usa pyev. É muito rápido, principalmente por causa do pyev. Ele tenta fornecer uma interface semelhante, distorcida com algumas pequenas alterações.
fonte
Tente também o Syncless . É baseado em corotina (portanto, é semelhante a Concurrence, Eventlet e gevent). Ele implementa substituições sem bloqueio de entrada para socket.socket, socket.gethostbyname (etc.), ssl.SSLSocket, time.sleep e select.select. É rápido. Ele precisa de Stackless Python e libevent. Ele contém uma extensão Python obrigatória escrita em C (Pyrex / Cython).
fonte
Confirmo a bondade da sincronia . Ele pode usar a libev (a versão mais recente, limpa e de melhor desempenho da libevent). Algumas vezes atrás, ele não tem tanto suporte quanto o libevent, mas agora o processo de desenvolvimento vai além e é muito útil.
fonte
Se você quer apenas uma biblioteca de solicitações HTTP simplificada e leve, acho o Unirest realmente bom
fonte
Você pode dar uma olhada no PyWorks, que tem uma abordagem bem diferente. Ele permite que instâncias de objetos sejam executadas em seu próprio encadeamento e faz chamadas de função para esse objeto assíncronas.
Apenas deixe uma classe herdar da tarefa em vez do objeto e ela é assíncrona; todas as chamadas de métodos são proxies. Os valores de retorno (se você precisar deles) são proxies futuros.
O PyWorks pode ser encontrado em http://bitbucket.org/raindog/pyworks
fonte