фоновая функция в Python - PullRequest
       34

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

68 голосов
/ 24 августа 2011

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

Ответы [ 3 ]

95 голосов
/ 24 августа 2011

Сделайте что-то вроде этого:

def function_that_downloads(my_args):
    # do some long download here

затем вставьте, сделайте что-то вроде этого:

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()

6 голосов
/ 24 августа 2011

Обычно способ сделать это состоит в том, чтобы использовать пул потоков и ставить в очередь загрузки, которые будут выдавать сигнал, то есть событие, о том, что задача завершила обработку.Вы можете сделать это в рамках модуля потоков , предоставляемого 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

Обратите внимание, что здесь не установлен флаг демона.

3 голосов
/ 24 августа 2011

Я предпочитаю использовать 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 переключает контексты, когда есть другие "зелень "бегает.Беспокойство по поводу блокировки и т. Д. Значительно уменьшено, поскольку одновременно выполняется только одна вещь, но изображение будет продолжать загружаться всякий раз, когда в основном контексте выполняется операция блокировки.

В зависимости от того, сколькои что вы хотите делать в фоновом режиме, это может быть лучше или хуже, чем решения на основе потоков;конечно, это гораздо более масштабируемо (то есть вы можете делать гораздо больше вещей в фоновом режиме), но это может не беспокоить в текущей ситуации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...