portaldacalheta.pt
  • Principal
  • Noticias Do Mundo
  • Lucratividade E Eficiência
  • Ágil
  • Família
Processo Interno

Tutorial de multithreading e multiprocessamento em Python



Nota: Por solicitação popular para demonstrar algumas técnicas alternativas --- incluindo async / await, disponível apenas desde o advento do Python 3.5 --- eu adicionei algumas atualizações no final do artigo . Aproveitar!

As discussões que criticam Python frequentemente falam sobre como é difícil usar Python para trabalhos multithread, apontando o dedo para o que é conhecido como bloqueio de interpretador global (carinhosamente conhecido como o GIL ) que evita que vários threads de código Python sejam executados simultaneamente. Devido a isso, o módulo multithreading Python não se comporta da maneira que você esperaria se você não for um Desenvolvedor Python e você está vindo de outras linguagens como C ++ ou Java. Deve ficar claro que ainda é possível escrever código em Python que seja executado simultaneamente ou em paralelo e fazer uma grande diferença no desempenho resultante, desde que certas coisas sejam levadas em consideração. Se você ainda não leu, sugiro que dê uma olhada no Eqbal Alcorão artigo sobre simultaneidade e paralelismo em Ruby aqui no ApeeScape Engineering Blog.

Neste tutorial de simultaneidade Python, escreveremos um pequeno script Python para baixar as imagens mais populares do Imgur. Começaremos com uma versão que baixa as imagens sequencialmente ou uma de cada vez. Como pré-requisito, você terá que se registrar um aplicativo no Imgur . Se você ainda não possui uma conta Imgur, crie uma primeiro.



Os scripts nesses exemplos de threading foram testados com Python 3.6.4. Com algumas alterações, eles também devem ser executados com Python 2 - urllib é o que mais mudou entre essas duas versões de Python.



tutorial powerpivot passo a passo

Introdução ao multithreading Python

Vamos começar criando um módulo Python, denominado download.py. Este arquivo conterá todas as funções necessárias para buscar a lista de imagens e baixá-las. Vamos dividir essas funcionalidades em três funções separadas:



  • get_links
  • download_link
  • setup_download_dir

A terceira função, setup_download_dir, será usada para criar um diretório de destino do download, se ainda não existir.

A API de Imgur requer solicitações HTTP para suportar o Authorization cabeçalho com o ID do cliente. Você pode encontrar esse ID do cliente no painel do aplicativo que você registrou no Imgur e a resposta será codificada em JSON. Podemos usar a biblioteca JSON padrão do Python para decodificá-lo. Baixar a imagem é uma tarefa ainda mais simples, pois tudo o que você precisa fazer é buscar a imagem pelo URL e gravá-la em um arquivo.



Esta é a aparência do script:

import json import logging import os from pathlib import Path from urllib.request import urlopen, Request logger = logging.getLogger(__name__) types = {'image/jpeg', 'image/png'} def get_links(client_id): headers = {'Authorization': 'Client-ID {}'.format(client_id)} req = Request('https://api.imgur.com/3/gallery/random/random/', headers=headers, method='GET') with urlopen(req) as resp: data = json.loads(resp.read().decode('utf-8')) return [item['link'] for item in data['data'] if 'type' in item and item['type'] in types] def download_link(directory, link): download_path = directory / os.path.basename(link) with urlopen(link) as image, download_path.open('wb') as f: f.write(image.read()) logger.info('Downloaded %s', link) def setup_download_dir(): download_dir = Path('images') if not download_dir.exists(): download_dir.mkdir() return download_dir

A seguir, precisaremos escrever um módulo que usará essas funções para baixar as imagens, uma por uma. Chamaremos isso de single.py. Ele conterá a função principal de nossa primeira versão ingênua do downloader de imagens Imgur. O módulo recuperará o ID do cliente Imgur na variável de ambiente IMGUR_CLIENT_ID. Ele invocará o setup_download_dir para criar o diretório de destino do download. Finalmente, ele irá buscar uma lista de imagens usando o get_links , filtre todos os GIF e URLs de álbum e use download_link para baixar e salvar cada uma dessas imagens no disco. Aqui está o que single.py parece:



import logging import os from time import time from download import setup_download_dir, get_links, download_link logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) def main(): ts = time() client_id = os.getenv('IMGUR_CLIENT_ID') if not client_id: raise Exception('Couldn't find IMGUR_CLIENT_ID environment variable!') download_dir = setup_download_dir() links = get_links(client_id) for link in links: download_link(download_dir, link) logging.info('Took %s seconds', time() - ts) if __name__ == '__main__': main()

No meu laptop, este script levou 19,4 segundos para baixar 91 imagens. Observe que esses números podem variar de acordo com a rede em que você está. 19,4 segundos não é muito longo, mas e se quiséssemos baixar mais fotos? Talvez 900 imagens, em vez de 90. Com uma média de 0,2 segundos por foto, 900 imagens levariam aproximadamente 3 minutos. Para 9.000 fotos, demoraria 30 minutos. A boa notícia é que, introduzindo simultaneidade ou paralelismo, podemos acelerar isso drasticamente.

Todos os exemplos de código subsequentes mostrarão apenas instruções de importação que são novas e específicas para esses exemplos. Por conveniência, todos esses scripts Python podem ser encontrados em este repositório GitHub .



Simultaneidade e paralelismo em Python: exemplo de threading

Threading é uma das abordagens mais conhecidas para obter simultaneidade e paralelismo do Python. Encadeamento é um recurso normalmente fornecido pelo sistema operacional. Threads são mais leves do que processos e compartilham o mesmo espaço de memória.

Modelo de memória multithreading Python



Neste exemplo de threading Python, vamos escrever um novo módulo para substituir single.py. Este módulo criará um pool de oito threads, totalizando nove threads, incluindo o thread principal. Escolhi oito threads de trabalho porque meu computador tem oito núcleos de CPU e um thread de trabalho por núcleo parecia um bom número para quantos threads executar de uma vez. Na prática, esse número é escolhido com muito mais cuidado com base em outros fatores, como outros aplicativos e serviços executados na mesma máquina.

É quase igual ao anterior, com a exceção de que agora temos uma nova classe, DownloadWorker, que é descendente do Python Thread classe. O método run foi sobrescrito, o que executa um loop infinito. Em cada iteração, ele chama self.queue.get() para tentar buscar um URL de uma fila thread-safe. Ele bloqueia até que haja um item na fila para o trabalhador processar. Depois que o trabalhador recebe um item da fila, ele chama o mesmo download_link método que foi usado no script anterior para baixar a imagem para o diretório de imagens. Após a conclusão do download, o trabalhador sinaliza à fila que a tarefa foi concluída. Isso é muito importante, porque a Fila mantém registro de quantas tarefas foram enfileiradas. A chamada para queue.join() bloquearia o thread principal para sempre se os trabalhadores não sinalizassem que concluíram uma tarefa.



import logging import os from queue import Queue from threading import Thread from time import time from download import setup_download_dir, get_links, download_link logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) class DownloadWorker(Thread): def __init__(self, queue): Thread.__init__(self) self.queue = queue def run(self): while True: # Get the work from the queue and expand the tuple directory, link = self.queue.get() try: download_link(directory, link) finally: self.queue.task_done() def main(): ts = time() client_id = os.getenv('IMGUR_CLIENT_ID') if not client_id: raise Exception('Couldn't find IMGUR_CLIENT_ID environment variable!') download_dir = setup_download_dir() links = get_links(client_id) # Create a queue to communicate with the worker threads queue = Queue() # Create 8 worker threads for x in range(8): worker = DownloadWorker(queue) # Setting daemon to True will let the main thread exit even though the workers are blocking worker.daemon = True worker.start() # Put the tasks into the queue as a tuple for link in links: logger.info('Queueing {}'.format(link)) queue.put((download_dir, link)) # Causes the main thread to wait for the queue to finish processing all the tasks queue.join() logging.info('Took %s', time() - ts) if __name__ == '__main__': main()

A execução deste script de exemplo de threading Python na mesma máquina usada anteriormente resulta em um tempo de download de 4,1 segundos! Isso é 4,7 vezes mais rápido que o exemplo anterior. Embora seja muito mais rápido, vale a pena mencionar que apenas um thread estava em execução por vez ao longo deste processo devido ao GIL. Portanto, esse código é simultâneo, mas não paralelo. A razão de ainda ser mais rápida é porque essa é uma tarefa vinculada a IO. O processador quase não está suando ao baixar essas imagens, e a maior parte do tempo é gasto esperando pela rede. É por isso que o multithreading Python pode fornecer um grande aumento de velocidade. O processador pode alternar entre os threads sempre que um deles estiver pronto para fazer algum trabalho. Usar o módulo de threading em Python ou qualquer outra linguagem interpretada com um GIL pode realmente resultar em desempenho reduzido. Se o seu código estiver executando uma tarefa vinculada à CPU, como descompactar arquivos gzip, usando threading módulo resultará em um tempo de execução mais lento. Para tarefas vinculadas à CPU e execução verdadeiramente paralela, podemos usar o módulo de multiprocessamento.

Enquanto o de fato implementação de Python de referência - CPython - tem um GIL, isso não é verdade para todas as implementações de Python. Por exemplo, IronPython, uma implementação Python usando a estrutura .NET, não tem um GIL, e nem Jython, a implementação baseada em Java. Você pode encontrar uma lista de implementações Python funcionais Aqui .

Relacionado: Melhores práticas e dicas de Python por desenvolvedores do ApeeScape

Simultaneidade e paralelismo em Python, exemplo 2: gerando vários processos

O módulo de multiprocessamento é mais fácil de inserir do que o módulo de threading, já que não precisamos adicionar uma classe como o exemplo de threading Python. As únicas alterações que precisamos fazer estão na função principal.

Tutorial de multiprocessamento Python: Módulos

Para usar vários processos, criamos um multiprocessamento Pool. Com o método de mapa que ele fornece, passaremos a lista de URLs para o pool, que por sua vez gerará oito novos processos e usará cada um para baixar as imagens em paralelo. Esse é o verdadeiro paralelismo, mas tem um custo. Toda a memória do script é copiada em cada subprocesso que é gerado. Neste exemplo simples, não é um grande problema, mas pode facilmente se tornar uma sobrecarga séria para programas não triviais.

import logging import os from functools import partial from multiprocessing.pool import Pool from time import time from download import setup_download_dir, get_links, download_link logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logging.getLogger('requests').setLevel(logging.CRITICAL) logger = logging.getLogger(__name__) def main(): ts = time() client_id = os.getenv('IMGUR_CLIENT_ID') if not client_id: raise Exception('Couldn't find IMGUR_CLIENT_ID environment variable!') download_dir = setup_download_dir() links = get_links(client_id) download = partial(download_link, download_dir) with Pool(4) as p: p.map(download, links) logging.info('Took %s seconds', time() - ts) if __name__ == '__main__': main()

Simultaneidade e paralelismo em Python, exemplo 3: distribuição para vários trabalhadores

Embora os módulos de threading e multiprocessamento sejam ótimos para scripts que estão sendo executados em seu computador pessoal, o que você deve fazer se quiser que o trabalho seja feito em uma máquina diferente ou se precisar escalar para mais do que a CPU em uma máquina pode lidar com? Um ótimo caso de uso para isso são as tarefas de back-end de longa execução para aplicativos da web. Se você tem algumas tarefas de longa execução, não quer girar um monte de subprocessos ou threads na mesma máquina que precisam executar o resto do código do aplicativo. Isso degradará o desempenho do seu aplicativo para todos os seus usuários. O que seria ótimo é poder executar essas tarefas em outra máquina, ou em muitas outras máquinas.

Uma ótima biblioteca Python para esta tarefa é RQ , uma biblioteca muito simples, mas poderosa. Você primeiro enfileira uma função e seus argumentos usando a biblioteca. este picles a representação da chamada de função, que é então anexada a um Redis Lista. Enfileirar o trabalho é a primeira etapa, mas não fará nada ainda. Também precisamos de pelo menos um trabalhador para escutar nessa fila de trabalhos.

Modelo da biblioteca de filas RQ Python

tratamento de exceções em bota de mola

A primeira etapa é instalar e executar um servidor Redis em seu computador ou ter acesso a um servidor Redis em execução. Depois disso, existem apenas algumas pequenas alterações feitas no código existente. Primeiro criamos uma instância de uma fila RQ e passamos a ela uma instância de um servidor Redis do biblioteca redis-py . Então, em vez de apenas chamar nosso download_link método, chamamos q.enqueue(download_link, download_dir, link). O método enqueue recebe uma função como seu primeiro argumento, então quaisquer outros argumentos ou argumentos de palavra-chave são transmitidos para essa função quando o trabalho é realmente executado.

Uma última etapa que precisamos fazer é iniciar alguns trabalhadores. O RQ fornece um script útil para executar workers na fila padrão. Basta executar rqworker em uma janela de terminal e isso iniciará um trabalhador ouvindo na fila padrão. Certifique-se de que seu diretório de trabalho atual seja o mesmo de onde residem os scripts. Se desejar ouvir uma fila diferente, você pode executar rqworker queue_name e ouvirá essa fila nomeada. A grande vantagem do RQ é que, desde que você possa se conectar ao Redis, poderá executar quantos workers quiser em quantas máquinas diferentes quiser; portanto, é muito fácil escalar conforme seu aplicativo cresce. Aqui está a fonte para a versão RQ:

import logging import os from redis import Redis from rq import Queue from download import setup_download_dir, get_links, download_link logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logging.getLogger('requests').setLevel(logging.CRITICAL) logger = logging.getLogger(__name__) def main(): client_id = os.getenv('IMGUR_CLIENT_ID') if not client_id: raise Exception('Couldn't find IMGUR_CLIENT_ID environment variable!') download_dir = setup_download_dir() links = get_links(client_id) q = Queue(connection=Redis(host='localhost', port=6379)) for link in links: q.enqueue(download_link, download_dir, link) if __name__ == '__main__': main()

No entanto, RQ não é a única solução de fila de tarefas do Python. RQ é fácil de usar e cobre casos de uso simples extremamente bem, mas se opções mais avançadas forem necessárias, outras soluções de fila Python 3 (como Salsão ) pode ser usado.

Python Multithreading vs. Multiprocessamento

Se seu código for limitado por IO, tanto o multiprocessamento quanto o multithreading em Python funcionarão para você. O multiprocessamento é mais fácil de incluir do que o threading, mas tem uma sobrecarga de memória maior. Se o seu código estiver vinculado à CPU, o multiprocessamento provavelmente será a melhor escolha - especialmente se a máquina de destino tiver vários núcleos ou CPUs. Para aplicativos da web, e quando você precisar dimensionar o trabalho em várias máquinas, o RQ será melhor para você.

Relacionado: Torne-se mais avançado: evite os 10 erros mais comuns cometidos por programadores de Python

Atualizar

Python concurrent.futures

Algo novo desde o Python 3.2 que não foi mencionado no artigo original é o concurrent.futures pacote. Este pacote fornece ainda outra maneira de usar simultaneidade e paralelismo com Python.

ponto de venda baseado em android

No artigo original, mencionei que o módulo de multiprocessamento do Python seria mais fácil de inserir no código existente do que o módulo de threading. Isso acontecia porque o módulo de threading do Python 3 exigia a subclasse de Thread e também criando uma classe Queue para os threads monitorarem o trabalho.

Usando um concurrent.futures.ThreadPoolExecutor torna o código de exemplo de threading Python quase idêntico ao módulo de multiprocessamento.

import logging import os from concurrent.futures import ThreadPoolExecutor from functools import partial from time import time from download import setup_download_dir, get_links, download_link logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) def main(): client_id = os.getenv('IMGUR_CLIENT_ID') if not client_id: raise Exception('Couldn't find IMGUR_CLIENT_ID environment variable!') download_dir = setup_download_dir() links = get_links(client_id) # By placing the executor inside a with block, the executors shutdown method # will be called cleaning up threads. # # By default, the executor sets number of workers to 5 times the number of # CPUs. with ThreadPoolExecutor() as executor: # Create a new partially applied function that stores the directory # argument. # # This allows the download_link function that normally takes two # arguments to work with the map function that expects a function of a # single argument. fn = partial(download_link, download_dir) # Executes fn concurrently using threads on the links iterable. The # timeout is for the entire process, not a single call, so downloading # all images must complete within 30 seconds. executor.map(fn, links, timeout=30) if __name__ == '__main__': main()

Agora que baixamos todas essas imagens com nosso Python ThreadPoolExecutor, podemos usá-las para testar uma tarefa vinculada à CPU. Podemos criar versões em miniatura de todas as imagens em um script de processo único de thread único e, em seguida, testar uma solução baseada em multiprocessamento.

Vamos usar o Travesseiro biblioteca para lidar com o redimensionamento das imagens.

Aqui está nosso script inicial.

import logging from pathlib import Path from time import time from PIL import Image logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) def create_thumbnail(size, path): ''' Creates a thumbnail of an image with the same name as image but with _thumbnail appended before the extension. E.g.: >>> create_thumbnail((128, 128), 'image.jpg') A new thumbnail image is created with the name image_thumbnail.jpg :param size: A tuple of the width and height of the image :param path: The path to the image file :return: None ''' image = Image.open(path) image.thumbnail(size) path = Path(path) name = path.stem + '_thumbnail' + path.suffix thumbnail_path = path.with_name(name) image.save(thumbnail_path) def main(): ts = time() for image_path in Path('images').iterdir(): create_thumbnail((128, 128), image_path) logging.info('Took %s', time() - ts) if __name__ == '__main__': main()

Este script itera sobre os caminhos no images pasta e para cada caminho ele executa a função create_thumbnail. Esta função usa Pillow para abrir a imagem, criar uma miniatura e salvar a nova imagem menor com o mesmo nome da original, mas com _thumbnail anexado ao nome.

A execução desse script em 160 imagens, totalizando 36 milhões, leva 2,32 segundos. Vamos ver se podemos acelerar isso usando um ProcessPoolExecutor .

import logging from pathlib import Path from time import time from functools import partial from concurrent.futures import ProcessPoolExecutor from PIL import Image logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) def create_thumbnail(size, path): ''' Creates a thumbnail of an image with the same name as image but with _thumbnail appended before the extension. E.g.: >>> create_thumbnail((128, 128), 'image.jpg') A new thumbnail image is created with the name image_thumbnail.jpg :param size: A tuple of the width and height of the image :param path: The path to the image file :return: None ''' path = Path(path) name = path.stem + '_thumbnail' + path.suffix thumbnail_path = path.with_name(name) image = Image.open(path) image.thumbnail(size) image.save(thumbnail_path) def main(): ts = time() # Partially apply the create_thumbnail method, setting the size to 128x128 # and returning a function of a single argument. thumbnail_128 = partial(create_thumbnail, (128, 128)) # Create the executor in a with block so shutdown is called when the block # is exited. with ProcessPoolExecutor() as executor: executor.map(thumbnail_128, Path('images').iterdir()) logging.info('Took %s', time() - ts) if __name__ == '__main__': main()

O create_thumbnail método é idêntico ao último script. A principal diferença é a criação de um ProcessPoolExecutor. Do executor mapa método é usado para criar as miniaturas em paralelo. Por padrão, o ProcessPoolExecutor cria um subprocesso por CPU. A execução desse script nas mesmas 160 imagens levou 1,05 segundos - 2,2 vezes mais rápido!

Async / Await (somente Python 3.5+)

Um dos itens mais solicitados nos comentários do artigo original foi um exemplo usando Python 3 assíncio módulo. Em comparação com os outros exemplos, há algumas novas sintaxes Python que podem ser novas para a maioria das pessoas e também alguns novos conceitos. Uma infeliz camada adicional de complexidade é causada pelo urllib integrado do Python | módulo não sendo assíncrono. Precisaremos usar uma biblioteca HTTP assíncrona para obter todos os benefícios do asyncio. Para isso, vamos usar aiohttp .

Vamos direto ao código e uma explicação mais detalhada virá a seguir.

import asyncio import logging import os from time import time import aiohttp from download import setup_download_dir, get_links logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) async def async_download_link(session, directory, link): ''' Async version of the download_link method we've been using in the other examples. :param session: aiohttp ClientSession :param directory: directory to save downloads :param link: the url of the link to download :return: ''' download_path = directory / os.path.basename(link) async with session.get(link) as response: with download_path.open('wb') as f: while True: # await pauses execution until the 1024 (or less) bytes are read from the stream chunk = await response.content.read(1024) if not chunk: # We are done reading the file, break out of the while loop break f.write(chunk) logger.info('Downloaded %s', link) # Main is now a coroutine async def main(): client_id = os.getenv('IMGUR_CLIENT_ID') if not client_id: raise Exception('Couldn't find IMGUR_CLIENT_ID environment variable!') download_dir = setup_download_dir() # We use a session to take advantage of tcp keep-alive # Set a 3 second read and connect timeout. Default is 5 minutes async with aiohttp.ClientSession(conn_timeout=3, read_timeout=3) as session: tasks = [(async_download_link(session, download_dir, l)) for l in get_links(client_id)] # gather aggregates all the tasks and schedules them in the event loop await asyncio.gather(*tasks, return_exceptions=True) if __name__ == '__main__': ts = time() # Create the asyncio event loop loop = asyncio.get_event_loop() try: loop.run_until_complete(main()) finally: # Shutdown the loop even if there is an exception loop.close() logger.info('Took %s seconds to complete', time() - ts)

Há bastante coisas para desempacotar aqui. Vamos começar com o ponto de entrada principal do programa. A primeira coisa que fazemos com o módulo asyncio é obter o loop de eventos. O loop de eventos lida com todo o código assíncrono. Em seguida, o loop é executado até ser concluído e aprovado no main função. Há uma nova sintaxe na definição de main: async def. Você também notará que await e with async.

node js call rest api

A sintaxe async / await foi introduzida em PEP492 . O async def sintaxe marca uma função como um co-rotina . Internamente, as corrotinas são baseadas em geradores Python, mas não são exatamente a mesma coisa. As corrotinas retornam um objeto de corrotina semelhante a como os geradores retornam um objeto gerador. Depois de ter uma co-rotina, você obtém seus resultados com await expressão. Quando uma co-rotina chama await, a execução da co-rotina é suspensa até que o aguardável seja concluído. Esta suspensão permite que outro trabalho seja concluído enquanto a co-rotina está suspensa “aguardando” algum resultado. Em geral, esse resultado será algum tipo de I / O como uma solicitação de banco de dados ou, em nosso caso, uma solicitação HTTP.

O download_link função teve que ser alterada de forma bastante significativa. Anteriormente, confiávamos em urllib para fazer o fardo do trabalho de leitura da imagem para nós. Agora, para permitir que nosso método funcione corretamente com o paradigma de programação assíncrona, introduzimos um while loop que lê pedaços da imagem por vez e suspende a execução enquanto espera a conclusão da E / S. Isso permite que o loop de eventos faça um loop no download das diferentes imagens, pois cada uma tem novos dados disponíveis durante o download.

Deve haver uma - de preferência apenas uma - maneira óbvia de fazer isso

Enquanto o zen de Python nos diz que deve haver uma maneira óbvia de fazer algo, há muitas maneiras em Python de introduzir simultaneidade em nossos programas. O melhor método a escolher dependerá do seu caso de uso específico. O paradigma assíncrono escala melhor para cargas de trabalho de alta simultaneidade (como um servidor da web) em comparação com threading ou multiprocessamento, mas requer que seu código (e dependências) seja assíncrono para se beneficiar totalmente.

Esperançosamente, os exemplos de threading do Python neste artigo - e atualização - apontarão na direção certa para que você tenha uma ideia de onde procurar na biblioteca padrão do Python se precisar introduzir simultaneidade em seus programas.

Compreender o básico

O que é um tópico em Python?

Um thread é um processo ou tarefa leve. Um thread é uma forma de adicionar simultaneidade aos seus programas. Se seu aplicativo Python estiver usando vários threads e você observar os processos em execução em seu sistema operacional, verá apenas uma única entrada para o seu script, embora ele esteja executando vários threads.

O que é multithreading?

Multithreading (às vezes simplesmente 'threading') é quando um programa cria vários threads com execução cíclica entre eles, então uma tarefa de execução mais longa não bloqueia todas as outras. Isso funciona bem para tarefas que podem ser divididas em subtarefas menores, que podem então ser atribuídas a um thread a ser concluído.

Qual é a diferença entre Python threading e multiprocessamento?

Com o encadeamento, a simultaneidade é obtida usando vários encadeamentos, mas devido ao GIL, apenas um encadeamento pode ser executado por vez. No multiprocessamento, o processo original é bifurcado em vários processos filho ignorando o GIL. Cada processo filho terá uma cópia de toda a memória do programa.

Como o multithreading e o multiprocessamento do Python estão relacionados?

Tanto o multithreading quanto o multiprocessamento permitem que o código Python seja executado simultaneamente. Somente o multiprocessamento permitirá que seu código seja verdadeiramente paralelo. No entanto, se seu código tiver muito IO (como solicitações HTTP), o multithreading provavelmente ainda acelerará seu código.

Dissecando os meandros da anatomia da tipografia (com infográfico)

Ferramentas E Tutoriais

Dissecando os meandros da anatomia da tipografia (com infográfico)
Derek Chauvin condenado a 22 anos e seis meses de prisão pela morte de George Floyd

Derek Chauvin condenado a 22 anos e seis meses de prisão pela morte de George Floyd

Mundo

Publicações Populares
Quem, o quê e por quê - um guia para métodos de teste do usuário
Quem, o quê e por quê - um guia para métodos de teste do usuário
Aflição financeira em uma crise: você não pode prever, você pode se preparar
Aflição financeira em uma crise: você não pode prever, você pode se preparar
Bangladesh condena seis militantes à morte por matar dois ativistas gays
Bangladesh condena seis militantes à morte por matar dois ativistas gays
Mães solteiras na arte de criar filhos sozinhas
Mães solteiras na arte de criar filhos sozinhas
Vender uma empresa para valor máximo em um mercado desafiador de fusões e aquisições
Vender uma empresa para valor máximo em um mercado desafiador de fusões e aquisições
 
Robo-conselheiro Risco de portfólio da indústria: eficiência ou redução de cantos?
Robo-conselheiro Risco de portfólio da indústria: eficiência ou redução de cantos?
EUA: corrida para prefeito de Honolulu segue para segundo turno
EUA: corrida para prefeito de Honolulu segue para segundo turno
13 podcasts que todo designer deve ouvir
13 podcasts que todo designer deve ouvir
Vazamentos de Panama Papers podem dar a Sanders algum poder de fogo contra o rival Clinton
Vazamentos de Panama Papers podem dar a Sanders algum poder de fogo contra o rival Clinton
Com 21 anos e raízes de Kerala, é o mais jovem na lista de MBE do Queen
Com 21 anos e raízes de Kerala, é o mais jovem na lista de MBE do Queen
Publicações Populares
  • estatísticas de adesão ao ginásio por mês
  • tutorial da API da web asp net
  • guia de estudo do arquiteto de soluções certificado pelo aws: exame associado saa-c01
  • como fazer simulação monte carlo
  • qual é a diferença entre c corp e s corp
  • o que é uma rodada baixa
Categorias
  • Noticias Do Mundo
  • Lucratividade E Eficiência
  • Ágil
  • Família
  • © 2022 | Todos Os Direitos Reservados

    portaldacalheta.pt