Ich habe ein Python-Skript, das dem Benutzer manchmal Bilder anzeigt. Die Bilder können manchmal ziemlich groß sein und werden häufig wiederverwendet. Das Anzeigen ist nicht kritisch, das Anzeigen der ihnen zugeordneten Nachricht jedoch. Ich habe eine Funktion, die das benötigte Bild herunterlädt und lokal speichert. Momentan wird es inline mit dem Code ausgeführt, der dem Benutzer eine Nachricht anzeigt. Bei nicht lokalen Bildern kann dies jedoch manchmal mehr als 10 Sekunden dauern. Gibt es eine Möglichkeit, diese Funktion bei Bedarf aufzurufen, sie jedoch im Hintergrund auszuführen, während der Code weiterhin ausgeführt wird? Ich würde nur ein Standardbild verwenden, bis das richtige verfügbar ist.
quelle
import threading, time; wait=lambda: time.sleep(2); t=threading.Thread(target=wait); t.start(); print('end')
). Ich hatte gehofft, dass "Hintergrund" auch losgelöst impliziert.subprocess
odermultiprocessing
Python untersuchen.add(a,b)
In der Regel besteht die Möglichkeit hierfür darin, einen Thread-Pool und Warteschlangen-Downloads zu verwenden, die ein Signal (auch als Ereignis bezeichnet) ausgeben, wenn die Verarbeitung dieser Aufgabe abgeschlossen ist. Sie können dies im Rahmen des von Python bereitgestellten Threading-Moduls tun .
Um diese Aktionen auszuführen, würde ich Ereignisobjekte und das Warteschlangenmodul verwenden .
Eine schnelle und schmutzige Demonstration dessen, was Sie mit einer einfachen
threading.Thread
Implementierung tun können, finden Sie unten: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()
Es wäre wahrscheinlich sinnvoll, nicht wie oben zu wählen. In diesem Fall würde ich den Code folgendermaßen ändern:
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
Beachten Sie, dass hier kein Daemon-Flag gesetzt ist.
quelle
Ich bevorzuge es, gevent für solche Dinge zu verwenden:
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()
Alles läuft in einem Thread, aber wenn eine Kerneloperation blockiert, wechselt gevent den Kontext, wenn andere "Greenlets" ausgeführt werden. Die Sorgen um das Sperren usw. sind stark reduziert, da jeweils nur eines ausgeführt wird. Das Image wird jedoch weiterhin heruntergeladen, wenn ein Blockierungsvorgang im "Haupt" -Kontext ausgeführt wird.
Je nachdem, wie viel und was Sie im Hintergrund tun möchten, kann dies entweder besser oder schlechter sein als Threading-basierte Lösungen. Natürlich ist es viel skalierbarer (dh Sie können viel mehr Dinge im Hintergrund tun), aber das ist in der aktuellen Situation möglicherweise nicht von Belang.
quelle
from gevent import monkey; monkey.patch_all()
?