Eu tenho um script Python que às vezes exibe imagens para o usuário. As imagens podem, às vezes, ser muito grandes e são reutilizadas com frequência. Exibi-los não é crítico, mas exibir a mensagem associada a eles é. Eu tenho uma função que baixa a imagem necessária e salva localmente. No momento, ele é executado em linha com o código que exibe uma mensagem para o usuário, mas às vezes pode levar mais de 10 segundos para imagens não locais. Existe uma maneira de chamar esta função quando necessário, mas executá-la em segundo plano enquanto o código continua a ser executado? Eu usaria apenas uma imagem padrão até que a correta estivesse disponível.
fonte
import threading, time; wait=lambda: time.sleep(2); t=threading.Thread(target=wait); t.start(); print('end')
). Eu esperava que "background" também implicasse desapego.subprocess
oumultiprocessing
python.add(a,b)
e obter o valor de retorno desse métodoNormalmente, a maneira de fazer isso seria usar um pool de threads e downloads de fila que emitiria um sinal, também conhecido como um evento, quando o processamento da tarefa fosse concluído. Você pode fazer isso dentro do escopo do módulo de threading fornecido pelo Python.
Para realizar essas ações, eu usaria objetos de evento e o módulo Queue .
No entanto, uma demonstração rápida e suja do que você pode fazer usando uma
threading.Thread
implementação simples pode ser vista abaixo:import os import threading import time import urllib2 class ImageDownloader(threading.Thread): def __init__(self, function_that_downloads): threading.Thread.__init__(self) self.runnable = function_that_downloads self.daemon = True def run(self): self.runnable() def downloads(): with open('somefile.html', 'w+') as f: try: f.write(urllib2.urlopen('http://google.com').read()) except urllib2.HTTPError: f.write('sorry no dice') print 'hi there user' print 'how are you today?' thread = ImageDownloader(downloads) thread.start() while not os.path.exists('somefile.html'): print 'i am executing but the thread has started to download' time.sleep(1) print 'look ma, thread is not alive: ', thread.is_alive()
Provavelmente faria sentido não pesquisar como estou fazendo acima. Nesse caso, eu mudaria o código para este:
import os import threading import time import urllib2 class ImageDownloader(threading.Thread): def __init__(self, function_that_downloads): threading.Thread.__init__(self) self.runnable = function_that_downloads def run(self): self.runnable() def downloads(): with open('somefile.html', 'w+') as f: try: f.write(urllib2.urlopen('http://google.com').read()) except urllib2.HTTPError: f.write('sorry no dice') print 'hi there user' print 'how are you today?' thread = ImageDownloader(downloads) thread.start() # show message thread.join() # display image
Observe que não há um sinalizador daemon definido aqui.
fonte
Eu prefiro usar gevent para este tipo de coisa:
import gevent from gevent import monkey; monkey.patch_all() greenlet = gevent.spawn( function_to_download_image ) display_message() # ... perhaps interaction with the user here # this will wait for the operation to complete (optional) greenlet.join() # alternatively if the image display is no longer important, this will abort it: #greenlet.kill()
Tudo é executado em um thread, mas sempre que uma operação do kernel é bloqueada, o gevent muda os contextos quando há outros "greenlets" em execução. As preocupações com o bloqueio, etc. são muito reduzidas, pois há apenas uma coisa em execução por vez, mas a imagem continuará a ser baixada sempre que uma operação de bloqueio for executada no contexto "principal".
Dependendo de quanto e de que tipo de coisa você deseja fazer em segundo plano, isso pode ser melhor ou pior do que soluções baseadas em encadeamento; certamente, é muito mais escalonável (ou seja, você pode fazer muito mais coisas em segundo plano), mas isso pode não ser motivo de preocupação na situação atual.
fonte
from gevent import monkey; monkey.patch_all()
:?