У меня есть сценарий Python, который иногда отображает изображения пользователю. Иногда изображения могут быть довольно большими, и они часто используются повторно. Их отображение не критично, но отображение связанного с ними сообщения критично. У меня есть функция, которая загружает необходимое изображение и сохраняет его локально. Прямо сейчас он запускается вместе с кодом, который отображает сообщение пользователю, но иногда это может занять более 10 секунд для нелокальных изображений. Есть ли способ вызвать эту функцию, когда она понадобится, но запустить ее в фоновом режиме, пока код продолжает выполняться? Я бы просто использовал изображение по умолчанию, пока не стал доступен правильный.
источник
import threading, time; wait=lambda: time.sleep(2); t=threading.Thread(target=wait); t.start(); print('end')
). Я надеялся, что "фон" тоже будет отстраненным.subprocess
илиmultiprocessing
python.add(a,b)
и получить возвращаемое значение этого методаОбычно способ сделать это - использовать пул потоков и загрузку очереди, которые будут выдавать сигнал, иначе говоря, событие, когда эта задача завершает обработку. Вы можете сделать это в рамках модуля потоковой передачи, который предоставляет Python.
Для выполнения указанных действий я бы использовал объекты событий и модуль Queue .
Однако быстрая и грязная демонстрация того, что вы можете сделать с помощью простой
threading.Thread
реализации, можно увидеть ниже: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()
Вероятно, имеет смысл не проводить опрос, как я делаю выше. В этом случае я бы изменил код на этот:
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
Обратите внимание, что здесь не установлен флаг демона.
источник
Я предпочитаю использовать gevent для таких вещей:
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()
Все выполняется в одном потоке, но всякий раз, когда операция ядра блокируется, gevent переключает контексты, когда выполняются другие «гринлеты». Беспокойство о блокировке и т. Д. Значительно сокращается, так как одновременно выполняется только одна вещь, но изображение будет продолжать загружаться всякий раз, когда операция блокировки выполняется в «основном» контексте.
В зависимости от того, сколько и что вы хотите делать в фоновом режиме, это может быть лучше или хуже, чем решения на основе потоков; конечно, он гораздо более масштабируемый (то есть вы можете делать гораздо больше в фоновом режиме), но в текущей ситуации это может не вызывать беспокойства.
источник
from gevent import monkey; monkey.patch_all()
:?