J'ai un script Python qui affiche parfois des images à l'utilisateur. Les images peuvent parfois être assez grandes et elles sont souvent réutilisées. Les afficher n'est pas critique, mais afficher le message qui leur est associé l'est. J'ai une fonction qui télécharge l'image nécessaire et l'enregistre localement. À l'heure actuelle, il est exécuté en ligne avec le code qui affiche un message à l'utilisateur, mais cela peut parfois prendre plus de 10 secondes pour les images non locales. Existe-t-il un moyen d'appeler cette fonction quand c'est nécessaire, mais de l'exécuter en arrière-plan pendant que le code continue de s'exécuter? J'utiliserais simplement une image par défaut jusqu'à ce que la bonne devienne disponible.
la source
import threading, time; wait=lambda: time.sleep(2); t=threading.Thread(target=wait); t.start(); print('end')
). J'espérais que "l'arrière-plan" impliquait également un détachement.subprocess
oumultiprocessing
python.add(a,b)
et obtenir la valeur de retour de cette méthodeEn règle générale, la façon de procéder serait d'utiliser un pool de threads et des téléchargements de file d'attente qui émettraient un signal, c'est-à-dire un événement, lorsque cette tâche a terminé son traitement. Vous pouvez le faire dans le cadre du module de threading fourni par Python.
Pour effectuer ces actions, j'utiliserais des objets événement et le module File d'attente .
Cependant, une démonstration rapide et sale de ce que vous pouvez faire en utilisant une
threading.Thread
implémentation simple peut être vue ci-dessous: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()
Il serait probablement logique de ne pas interroger comme je le fais ci-dessus. Dans ce cas, je changerais le code en ceci:
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
Notez qu'il n'y a pas d'indicateur de démon défini ici.
la source
Je préfère utiliser gevent pour ce genre de chose:
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()
Tout fonctionne dans un thread, mais chaque fois qu'une opération du noyau se bloque, gevent change de contexte quand il y a d'autres "greenlets" en cours d'exécution. Les soucis concernant le verrouillage, etc. sont beaucoup plus faibles, car il n'y a qu'une seule chose en cours d'exécution à la fois, mais l'image continuera à se télécharger chaque fois qu'une opération de blocage s'exécute dans le contexte "principal".
Selon la quantité et le type de chose que vous voulez faire en arrière-plan, cela peut être meilleur ou pire que les solutions basées sur les threads; il est certainement beaucoup plus évolutif (c'est-à-dire que vous pouvez faire beaucoup plus de choses en arrière-plan), mais cela peut ne pas être préoccupant dans la situation actuelle.
la source
from gevent import monkey; monkey.patch_all()
:?