фоновая функция в Python
У меня есть скрипт на Python, который иногда отображает изображения для пользователя. Изображения иногда могут быть довольно большими, и они часто используются повторно. Отображение их не является критическим, но отображение сообщения, связанного с ними. У меня есть функция, которая загружает изображение, необходимое и сохраняет его локально. Прямо сейчас он запускается в строке с кодом, который отображает сообщение пользователю, но иногда это может занять более 10 секунд для нелокальных изображений. Есть ли способ я могу вызвать эту функцию когда это необходимо, но запустить его в фоновом режиме, а код продолжает выполняться? Я бы просто использовал изображение по умолчанию, пока правильный не станет доступным.
3 ответов:
сделать что-то вроде этого:
def function_that_downloads(my_args): # do some long download hereзатем inline, сделайте что-то вроде этого:
import threading def my_inline_function(some_args): # do some stuff download_thread = threading.Thread(target=function_that_downloads, args=some_args) download_thread.start() # continue doing stuffвы можете проверить, если поток закончил, прежде чем перейти к другим вещам, позвонив
download_thread.isAlive()
как правило, способ сделать это будет использовать пул потоков и очереди загрузки, которые будут выдавать сигнал, а также событие, что задача завершила обработку. Вы можете сделать это в рамках резьбонарезной модуль Python предоставляет.
для выполнения указанных действий я бы использовал события и модуль очереди.
однако, быстрая и грязная демонстрация того, что вы можете сделать с помощью простого
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 переключает контексты, когда работают другие "гринлеты". Заботы о блокировке и т. д. значительно уменьшаются, поскольку одновременно выполняется только одна вещь, но изображение будет продолжать загружаться всякий раз, когда операция блокировки выполняется в "основном" контексте.
в зависимости от того, сколько и какую вещь вы хотите сделать в фоновом режиме, это может быть либо лучше, либо хуже, чем потоковые решения; конечно, это гораздо более масштабируемо (т. е. вы можете делать гораздо больше вещей в фоновом режиме), но это может не вызывать беспокойства в текущей ситуации.
Comments