Estou um pouco confuso sobre se o multithreading funciona ou não em Python.
Sei que tem havido muitas perguntas sobre isso e li muitas delas, mas ainda estou confuso. Sei por experiência própria e vi outras pessoas postarem suas próprias respostas e exemplos aqui no StackOverflow que o multithreading é realmente possível em Python. Então, por que todo mundo diz que o Python está bloqueado pelo GIL e que apenas um thread pode ser executado por vez? Claramente funciona. Ou há alguma distinção que não estou entendendo aqui?
Muitos participantes / participantes também mencionam que o threading é limitado porque não faz uso de vários núcleos. Mas eu diria que eles ainda são úteis porque funcionam simultaneamente e, portanto, fazem a carga de trabalho combinada mais rapidamente. Quero dizer, por que haveria mesmo um módulo de thread Python caso contrário?
Atualizar:
Obrigado por todas as respostas até agora. Pelo que entendi, o multithreading só será executado em paralelo para algumas tarefas de E / S, mas só pode ser executado um de cada vez para várias tarefas principais vinculadas à CPU.
Não tenho certeza do que isso significa para mim em termos práticos, então darei apenas um exemplo do tipo de tarefa que gostaria de multithread. Por exemplo, digamos que eu queira percorrer uma lista muito longa de strings e fazer algumas operações básicas com strings em cada item da lista. Se eu dividir a lista, enviar cada sublista para ser processada por meu código de loop / string em um novo encadeamento e enviar os resultados de volta em uma fila, essas cargas de trabalho serão executadas aproximadamente ao mesmo tempo? Mais importante, isso teoricamente irá acelerar o tempo que leva para executar o script?
Outro exemplo poderia ser se eu pudesse renderizar e salvar quatro imagens diferentes usando PIL em quatro threads diferentes e fazer com que isso fosse mais rápido do que processar as imagens uma a uma após a outra? Acho que esse componente de velocidade é o que realmente estou pensando, e não qual é a terminologia correta.
Eu também sei sobre o módulo de multiprocessamento, mas meu principal interesse agora é para cargas de tarefas pequenas a médias (10-30 segundos) e, portanto, acho que multithreading será mais apropriado porque os subprocessos podem demorar para iniciar.
fonte
Respostas:
O GIL não impede o threading. Tudo o que o GIL faz é certificar-se de que apenas um thread está executando o código Python por vez; o controle ainda alterna entre os threads.
O que o GIL impede então, é fazer uso de mais de um núcleo de CPU ou CPUs separadas para rodar threads em paralelo.
Isso se aplica apenas ao código Python. As extensões C podem liberar o GIL para permitir que vários threads de código C e um thread Python sejam executados em vários núcleos. Isso se estende à E / S controlada pelo kernel, como
select()
chamadas para leituras e gravações de soquete, fazendo com que o Python manipule eventos de rede de maneira razoavelmente eficiente em uma configuração multi-core multi-thread.O que muitas implantações de servidor fazem é executar mais de um processo Python, para permitir que o sistema operacional lide com a programação entre os processos para utilizar seus núcleos de CPU ao máximo. Você também pode usar a
multiprocessing
biblioteca para lidar com o processamento paralelo em vários processos de uma base de código e processo pai, se for adequado aos seus casos de uso.Observe que o GIL é aplicável apenas à implementação CPython; Jython e IronPython usam uma implementação de threading diferente (os threads de tempo de execução comuns Java VM e .NET, respectivamente).
Para abordar sua atualização diretamente: Qualquer tarefa que tentar obter um aumento de velocidade da execução paralela, usando código Python puro, não terá uma aceleração, pois o código Python encadeado está bloqueado para um encadeamento em execução por vez. Se você misturar extensões C e E / S, no entanto (como PIL ou operações numpy), qualquer código C pode ser executado em paralelo com um thread Python ativo.
O threading Python é ótimo para criar uma GUI responsiva ou para lidar com várias solicitações curtas da web em que I / O é o gargalo mais do que o código Python. Não é adequado para paralelizar código Python de computação intensiva, siga o
multiprocessing
módulo para tais tarefas ou delegue a uma biblioteca externa dedicada.fonte
urllib.urlopen()
?), Para chamar um script Python de dentro de uma GUI Python e chamar várias operações PIL (por exemploImage.transform()
) e numpy (por exemplonumpy.array()
) com threads. E você forneceu mais alguns exemplos em seu comentário, como o uso de vários tópicos para ler arquivos (por exemplof.read()
,?). Sei que uma lista exaustiva não é possível, só queria os tipos de exemplos que você deu em sua atualização. De qualquer forma, aceitei sua resposta :)urllib.urlopen()
chamaria os soquetes de rede, aguardar a E / S do soquete é uma excelente oportunidade para alternar threads e fazer outra coisa.Sim. :)
Você tem o baixo nível fio módulo e o nível mais elevado de threading módulo. Mas se você simplesmente deseja usar máquinas multicore, o módulo de multiprocessamento é o caminho a percorrer.
Citação dos documentos :
fonte
Threading é permitido em Python, o único problema é que o GIL irá garantir que apenas um thread seja executado por vez (sem paralelismo).
Então, basicamente, se você quiser multi-thread o código para acelerar o cálculo, ele não vai acelerar, pois apenas uma thread é executada por vez, mas se você usá-lo para interagir com um banco de dados, por exemplo, ele o fará.
fonte