Tengo un script de Python que a veces muestra imágenes al usuario. Las imágenes pueden, a veces, ser bastante grandes y se reutilizan con frecuencia. Mostrarlos no es crítico, pero mostrar el mensaje asociado con ellos sí lo es. Tengo una función que descarga la imagen necesaria y la guarda localmente. En este momento, se ejecuta en línea con el código que muestra un mensaje al usuario, pero eso a veces puede llevar más de 10 segundos para imágenes no locales. ¿Hay alguna forma de llamar a esta función cuando sea necesario, pero ejecutarla en segundo plano mientras el código continúa ejecutándose? Solo usaría una imagen predeterminada hasta que esté disponible la correcta.
fuente
import threading, time; wait=lambda: time.sleep(2); t=threading.Thread(target=wait); t.start(); print('end')
). Tenía la esperanza de que "antecedentes" también implicara desapego.subprocess
omultiprocessing
python en su lugar.add(a,b)
y obtener valor de retorno de ese métodoNormalmente, la forma de hacer esto sería usar un grupo de subprocesos y descargas en cola que emitirían una señal, también conocida como evento, cuando esa tarea haya terminado de procesarse. Puede hacer esto dentro del alcance del módulo de subprocesos que proporciona Python.
Para realizar dichas acciones, usaría objetos de eventos y el módulo Queue .
Sin embargo, a continuación se puede ver una demostración rápida y sucia de lo que puede hacer con una
threading.Thread
implementación simple :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()
Probablemente tendría sentido no sondear como lo estoy haciendo arriba. En cuyo caso, cambiaría el código a esto:
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
Tenga en cuenta que no hay ningún indicador de demonio establecido aquí.
fuente
Prefiero usar gevent para este tipo de cosas:
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()
Todo se ejecuta en un hilo, pero siempre que se bloquea una operación del núcleo, gevent cambia de contexto cuando hay otros "greenlets" en ejecución. Las preocupaciones sobre el bloqueo, etc. se reducen mucho, ya que solo hay una cosa ejecutándose a la vez, sin embargo, la imagen continuará descargándose siempre que se ejecute una operación de bloqueo en el contexto "principal".
Dependiendo de cuánto y qué tipo de cosas quiera hacer en segundo plano, esto puede ser mejor o peor que las soluciones basadas en subprocesos; ciertamente, es mucho más escalable (es decir, puede hacer muchas más cosas en segundo plano), pero eso podría no ser motivo de preocupación en la situación actual.
fuente
from gevent import monkey; monkey.patch_all()
:?