Estou tentando entender o encadeamento em Python. Examinei a documentação e os exemplos, mas, francamente, muitos exemplos são excessivamente sofisticados e estou tendo problemas para entendê-los.
Como você mostra claramente as tarefas sendo divididas para multiencadeamento?
Respostas:
Desde que essa pergunta foi feita em 2010, houve uma simplificação real de como executar multithreading simples com Python com mapa e pool .
O código abaixo vem de uma publicação de artigo / blog que você definitivamente deveria conferir (sem afiliação) - Paralelismo em uma linha: um modelo melhor para as tarefas de segmentação do dia a dia . Resumirei abaixo - acaba sendo apenas algumas linhas de código:
Qual é a versão multithread de:
Descrição
Implementação
multiprocessing.dummy
é exatamente o mesmo que o módulo de multiprocessamento, mas usa threads ( uma distinção importante - use vários processos para tarefas intensivas em CPU; threads para (e durante) E / S ):E o tempo resulta:
Passando vários argumentos (funciona assim apenas no Python 3.3 e posterior ):
Para passar várias matrizes:
Ou para passar uma constante e uma matriz:
Se você estiver usando uma versão anterior do Python, poderá passar vários argumentos por meio desta solução alternativa ).
(Obrigado a user136036 pelo comentário útil.)
fonte
with Pool(8) as p: p.map( *whatever* )
e se livrar das linhas de contabilidade também.Aqui está um exemplo simples: você precisa tentar alguns URLs alternativos e retornar o conteúdo do primeiro para responder.
É um caso em que o encadeamento é usado como uma otimização simples: cada sub-rosca está aguardando uma URL resolver e responder, a fim de colocar seu conteúdo na fila; cada thread é um daemon (não continuará o processo se o thread principal terminar - isso é mais comum do que não); o encadeamento principal inicia todos os sub-roscas, faz um
get
na fila para aguardar até que um deles faça um eput
, em seguida, emite os resultados e termina (o que elimina quaisquer sub-roscas que ainda possam estar em execução, já que são encadeamentos daemon).O uso adequado de threads no Python é invariavelmente conectado a operações de E / S (como o CPython não usa vários núcleos para executar tarefas ligadas à CPU de qualquer maneira, a única razão para o encadeamento não é bloquear o processo enquanto há uma espera por algumas E / S ) As filas são quase sempre a melhor maneira de aumentar o trabalho para threads e / ou coletar os resultados do trabalho, a propósito, e são intrinsecamente seguros para threads, portanto, evitam que você se preocupe com bloqueios, condições, eventos, semáforos e outros conceitos de coordenação / comunicação.
fonte
join()
método, pois isso faria o thread principal aguardar até que sejam concluídos sem consumir o processador constantemente verificando o valor. @ Alex: obrigado, é exatamente isso que eu precisava para entender como usar threads.Queue
nome do módulo porqueue
. O nome do método é o mesmo.s = q.get()
print s
@ krs013 Não é necessáriojoin
porque o Queue.get () está bloqueando.NOTA : Para paralelização real no Python, você deve usar o módulo de multiprocessamento para dividir vários processos que são executados em paralelo (devido ao bloqueio global do interpretador, os threads do Python fornecem intercalação, mas na verdade são executados em série, não em paralelo e são apenas útil ao intercalar operações de E / S).
No entanto, se você está apenas procurando intercalação (ou está executando operações de E / S que podem ser paralelizadas apesar do bloqueio global do intérprete), o módulo de encadeamento é o ponto de partida. Como um exemplo realmente simples, vamos considerar o problema de somar um grande intervalo somando subintervalos em paralelo:
Observe que o acima é um exemplo muito estúpido, pois não faz absolutamente nenhuma E / S e será executado serialmente, embora intercalado (com a sobrecarga adicional da alternância de contexto) no CPython devido ao bloqueio global do interpretador.
fonte
thread1
é executado até que seja concluído enquanto o encadeamento principal bloqueia, o mesmo acontece comthread2
o encadeamento principal e retoma e imprime os valores acumulados.super(SummingThread, self).__init__()
? Como em stackoverflow.com/a/2197625/806988Como outros mencionados, o CPython pode usar threads apenas para esperas de E / S devido ao GIL .
Se você deseja se beneficiar de vários núcleos para tarefas ligadas à CPU, use o multiprocessamento :
fonte
f
função. Paralelamente, o programa principal agora aguarda a saída do processo,join
seguindo-o. Se a parte principal acabou de sair, o subprocesso pode ou não ser executado até a conclusão, portanto,join
é recomendável fazer isso .map
função é aqui: stackoverflow.com/a/28463266/2327328Apenas uma observação: uma fila não é necessária para segmentação.
Este é o exemplo mais simples que eu poderia imaginar que mostra 10 processos em execução simultaneamente.
fonte
for
loop, você pode chamarthread.start()
no primeiro loop.A resposta de Alex Martelli me ajudou. No entanto, aqui está uma versão modificada que achei mais útil (pelo menos para mim).
Atualizado: funciona em Python 2 e Python 3
fonte
import Queue ModuleNotFoundError: No module named 'Queue'
Estou executando python 3.6.5 algumas mensagens mencionar que em python 3.6.5 ele équeue
, mas mesmo depois de eu mudar isso, ainda não funcionaDada uma função,
f
rosqueie-a assim:Para passar argumentos para
f
fonte
Thread
objeto é limpo. Veja os documentos . Existe umis_alive()
método que você pode usar para verificar um encadeamento, se necessário.is_alive
método, mas não consegui descobrir como aplicá-lo ao thread. Tentei atribuirthread1=threading.Thread(target=f).start()
e, em seguida, verificá-lo comthread1.is_alive()
, masthread1
é preenchido comNone
, então não há sorte lá. Você sabe se existe alguma outra maneira de acessar o thread?thread1=threading.Thread(target=f)
seguida porthread1.start()
. Então você pode fazerthread1.is_alive()
.thread1.is_alive()
retornosFalse
assim que a função sair.Achei isso muito útil: crie tantos threads quanto núcleos e permita que eles executem um número (grande) de tarefas (nesse caso, chamando um programa shell):
fonte
O Python 3 tem a facilidade de iniciar tarefas paralelas . Isso facilita nosso trabalho.
Possui pool de threads e pool de processos .
A seguir, é apresentado um insight:
Exemplo de ThreadPoolExecutor ( origem )
ProcessPoolExecutor ( origem )
fonte
Usando o novo módulo concurrent.futures
A abordagem do executor pode parecer familiar para todos aqueles que já sujaram as mãos com Java antes.
Também em uma nota lateral: para manter o universo saudável, não se esqueça de fechar seus pools / executores se você não usar o
with
contexto (o que é tão incrível que faz isso por você)fonte
Para mim, o exemplo perfeito de encadeamento é o monitoramento de eventos assíncronos. Veja este código.
Você pode jogar com esse código abrindo uma sessão IPython e fazendo algo como:
Espere alguns minutos
fonte
A maioria da documentação e dos tutoriais usa o Python
Threading
e oQueue
módulo, e eles podem parecer impressionantes para iniciantes.Talvez considere o
concurrent.futures.ThreadPoolExecutor
módulo do Python 3.Combinado com a compreensão de
with
cláusulas e listas, pode ser um verdadeiro encanto.fonte
Eu vi muitos exemplos aqui em que nenhum trabalho real estava sendo realizado, e eles eram principalmente ligados à CPU. Aqui está um exemplo de uma tarefa vinculada à CPU que calcula todos os números primos entre 10 e 10,05 milhões. Eu usei todos os quatro métodos aqui:
Aqui estão os resultados na minha máquina com quatro núcleos Mac OS X
fonte
if __name__ == '__main__':
antes da chamada principal, caso contrário, as desovas medição em si e gravuras Uma tentativa foi feita para iniciar um novo processo antes ... .Aqui está um exemplo muito simples de importação de CSV usando threading. (A inclusão da biblioteca pode diferir para propósitos diferentes.)
Funções auxiliares:
Função do driver:
fonte
Gostaria de contribuir com um exemplo simples e as explicações que achei úteis quando tive que resolver esse problema pessoalmente.
Nesta resposta, você encontrará algumas informações sobre o GIL (bloqueio global de intérpretes) do Python e um exemplo simples do dia-a-dia escrito usando multiprocessing.dummy, além de alguns benchmarks simples.
Bloqueio global de intérpretes (GIL)
Python não permite multi-threading no sentido mais verdadeiro da palavra. Ele tem um pacote multiencadeado, mas se você deseja multiencadear para acelerar seu código, geralmente não é uma boa ideia usá-lo.
O Python possui uma construção chamada bloqueio global de intérpretes (GIL). O GIL garante que apenas um dos seus 'threads' possa ser executado a qualquer momento. Um segmento adquire o GIL, faz um pouco de trabalho e passa o GIL para o próximo segmento.
Isso acontece muito rapidamente e, para o olho humano, pode parecer que seus threads estão executando paralelamente, mas na verdade eles estão apenas se revezando usando o mesmo núcleo da CPU.
Toda essa passagem do GIL adiciona sobrecarga à execução. Isso significa que, se você deseja que seu código seja executado mais rapidamente, o uso do pacote threading geralmente não é uma boa ideia.
Existem razões para usar o pacote de encadeamento do Python. Se você deseja executar algumas coisas simultaneamente, e a eficiência não é uma preocupação, é totalmente adequado e conveniente. Ou se você estiver executando um código que precisa esperar por algo (como algumas E / S), isso pode fazer muito sentido. Mas a biblioteca de threads não permitirá que você use núcleos extras da CPU.
A multithreading pode ser terceirizada para o sistema operacional (executando o multiprocessamento) e algum aplicativo externo que chama seu código Python (por exemplo, Spark ou Hadoop ) ou algum código que seu código Python chama (por exemplo: você pode faça com que seu código Python chame uma função C que faça o material multiencadeado caro).
Por que isso importa
Porque muitas pessoas passam muito tempo tentando encontrar gargalos em seu código multiencadeado Python sofisticado antes de aprenderem o que é o GIL.
Depois que essas informações estiverem claras, eis o meu código:
fonte
Aqui está o multi-threading com um exemplo simples que será útil. Você pode executá-lo e entender facilmente como o multi threading está funcionando no Python. Usei uma trava para impedir o acesso a outros threads até que os threads anteriores terminassem seu trabalho. Pelo uso dessa linha de código,
você pode permitir vários processos por vez e manter o restante dos encadeamentos que serão executados mais tarde ou depois dos processos anteriores.
fonte
Com o empréstimo desta publicação , sabemos sobre a escolha entre multithreading, multiprocessing e async /
asyncio
e seu uso.O Python 3 possui uma nova biblioteca interna para simultaneidade e paralelismo: concurrent.futures
Então, demonstrarei, através de um experimento, a execução de quatro tarefas (ou seja,
.sleep()
método) da seguinteThreading-Pool
maneira:Resultado:
[ NOTA ]:
multiprocessing
vsthreading
), poderá alterarThreadPoolExecutor
paraProcessPoolExecutor
.fonte
Nenhuma das soluções anteriores realmente usou vários núcleos no meu servidor GNU / Linux (onde eu não tenho direitos de administrador). Eles apenas rodavam em um único núcleo.
Eu usei a
os.fork
interface de nível inferior para gerar vários processos. Este é o código que funcionou para mim:fonte
fonte