фоновая функция в Python



У меня есть скрипт на Python, который иногда отображает изображения для пользователя. Изображения иногда могут быть довольно большими, и они часто используются повторно. Отображение их не является критическим, но отображение сообщения, связанного с ними. У меня есть функция, которая загружает изображение, необходимое и сохраняет его локально. Прямо сейчас он запускается в строке с кодом, который отображает сообщение пользователю, но иногда это может занять более 10 секунд для нелокальных изображений. Есть ли способ я могу вызвать эту функцию когда это необходимо, но запустить его в фоновом режиме, а код продолжает выполняться? Я бы просто использовал изображение по умолчанию, пока правильный не станет доступным.

616   3  

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

    Ничего не найдено.