Mam skrypt w Pythonie, który czasami wyświetla użytkownikowi obrazy. Obrazy mogą czasami być dość duże i często są ponownie wykorzystywane. Wyświetlanie ich nie jest krytyczne, ale wyświetlanie powiązanego z nimi komunikatu jest. Mam funkcję, która pobiera potrzebny obraz i zapisuje go lokalnie. W tej chwili jest uruchamiany w tekście z kodem, który wyświetla komunikat dla użytkownika, ale czasami może to zająć ponad 10 sekund w przypadku obrazów nielokalnych. Czy istnieje sposób, aby wywołać tę funkcję, gdy jest potrzebna, ale uruchomić ją w tle, podczas gdy kod nadal jest wykonywany? Po prostu użyłbym domyślnego obrazu, dopóki właściwy nie stanie się dostępny.
źródło
import threading, time; wait=lambda: time.sleep(2); t=threading.Thread(target=wait); t.start(); print('end')
). Miałem nadzieję, że „tło” sugerowało również brak relacji.subprocess
lubmultiprocessing
python.add(a,b)
i uzyskać wartośćZwykle sposobem na to byłoby użycie puli wątków i pobrań kolejki, które spowodowałyby wysłanie sygnału, czyli zdarzenia, po zakończeniu przetwarzania tego zadania. Możesz to zrobić w ramach modułu obsługi wątków, który zapewnia Python.
Aby wykonać te czynności, użyłbym obiektów zdarzeń i modułu Queue .
threading.Thread
Poniżej można jednak zobaczyć szybką i brudną demonstrację tego, co można zrobić za pomocą prostej implementacji: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()
Prawdopodobnie rozsądnie byłoby nie sondować tak, jak robię powyżej. W takim przypadku zmieniłbym kod na ten:
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
Zauważ, że nie ma tu ustawionej flagi demona.
źródło
Wolę używać gevent do tego typu rzeczy:
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()
Wszystko działa w jednym wątku, ale za każdym razem, gdy blokuje się operacja jądra, gevent zmienia konteksty, gdy są uruchomione inne „zielone środowiska”. Obawy o blokowanie itp. Są znacznie ograniczone, ponieważ w danym momencie działa tylko jedna rzecz, ale obraz będzie nadal pobierany, gdy operacja blokowania zostanie wykonana w kontekście „głównym”.
W zależności od tego, ile i jakiego rodzaju rzeczy chcesz robić w tle, może to być lepsze lub gorsze niż rozwiązania oparte na wątkach; z pewnością jest znacznie bardziej skalowalny (tj. możesz zrobić o wiele więcej rzeczy w tle), ale w obecnej sytuacji może to nie stanowić problemu.
źródło
from gevent import monkey; monkey.patch_all()
:?