Python의 백그라운드 함수


88

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

답변:


129

다음과 같이하십시오.

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


인터프리터는 스레드가 닫힐 때까지 열려 있습니다. (예 import threading, time; wait=lambda: time.sleep(2); t=threading.Thread(target=wait); t.start(); print('end')). 나는 "배경"도 분리되어 있기를 바라고 있었다.
ThorSummoner

3
@ThorSummoner 스레드는 모두 동일한 프로세스에 포함됩니다. 새 프로세스를 생성하려는 경우 대신 subprocess또는 multiprocessingpython 모듈 을 살펴 보는 것이 좋습니다.
TorelTwiddler 2016

@TorelTwiddler 백그라운드에서 함수를 실행하고 싶지만 리소스 제한이 있으며 원하는만큼 함수를 실행할 수 없으며 함수의 추가 실행을 대기열에 추가하고 싶습니다. 어떻게해야하는지 아십니까? 여기에 내 질문이 있습니다 . 제 질문 좀 봐주 시겠어요? 어떤 도움이라도 좋을 것입니다!
Amir

3
download_thread = threading.Thread (대상 = function_that_downloads, 인수 = (변수 1, 변수 2, variableN)) : 여러 매개 변수를 원하는 경우
georgeos을

방법이처럼 - 어떻게 여러 인수를 전달하는 방법 add(a,b)및 그 방법의 반환 값 얻을
Maifee UL 아사드

7

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

이 작업을 수행하기 위해 이벤트 객체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

나는 이런 종류의 일에 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"이 실행 중일 때 컨텍스트를 전환합니다. 한 번에 한 가지만 실행되기 때문에 잠금 등에 대한 걱정이 훨씬 줄어들지 만 "주"컨텍스트에서 차단 작업이 실행될 때마다 이미지가 계속 다운로드됩니다.

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


이 줄의 목적은 무엇 from gevent import monkey; monkey.patch_all()입니까?
nz_21

gevent 호환성을위한 패치 표준 라이브러리 -gevent.org/api/gevent.monkey.html
shaunc
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.