[python] Python의 백그라운드 함수

가끔 사용자에게 이미지를 표시하는 Python 스크립트가 있습니다. 이미지는 때때로 상당히 클 수 있으며 자주 재사용됩니다. 그것들을 표시하는 것은 중요하지 않지만 관련된 메시지를 표시하는 것은 중요합니다. 필요한 이미지를 다운로드하여 로컬에 저장하는 기능이 있습니다. 지금은 사용자에게 메시지를 표시하는 코드와 함께 인라인으로 실행되지만 로컬이 아닌 이미지의 경우 10 초 이상 걸릴 수 있습니다. 필요할 때이 함수를 호출 할 수 있지만 코드가 계속 실행되는 동안 백그라운드에서 실행할 수있는 방법이 있습니까? 올바른 이미지를 사용할 수있을 때까지 기본 이미지를 사용합니다.



답변

다음과 같이하십시오.

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, name="Downloader", args=some_args)
    download_thread.start()
    # continue doing stuff

다음을 호출하여 다른 작업을 진행하기 전에 스레드가 완료되었는지 확인할 수 있습니다. download_thread.isAlive()


답변

일반적으로이를 수행하는 방법은 작업이 처리를 완료했을 때 신호 (일명 이벤트)를 발행하는 스레드 풀 및 큐 다운로드를 사용하는 것입니다. 파이썬이 제공 하는 스레딩 모듈 의 범위 내에서이를 수행 할 수 있습니다 .

이 작업을 수행하기 위해 이벤트 객체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는 다른 “greenlet”이 실행 중일 때 컨텍스트를 전환합니다. 한 번에 한 가지만 실행되기 때문에 잠금 등에 대한 걱정이 훨씬 줄어들지 만 “주”컨텍스트에서 차단 작업이 실행될 때마다 이미지가 계속 다운로드됩니다.

백그라운드에서 수행하려는 작업의 양과 종류에 따라 스레딩 기반 솔루션보다 좋을 수도 있고 나쁠 수도 있습니다. 확실히 훨씬 더 확장 가능하지만 (즉, 백그라운드에서 더 많은 작업을 수행 할 수 있음) 현재 상황에서는 문제가되지 않을 수 있습니다.


답변