2011-08-23 55 views
48

我有一個Python腳本,有時會向用戶顯示圖像。圖像有時可能很大,而且經常重複使用。顯示它們並不重要,但是顯示與它們相關的消息是。我有一個功能可以下載所需的圖像並將其保存到本地。現在,它與向用戶顯示消息的代碼一起運行,但對於非本地圖像,有時會花費10秒以上。有什麼方法可以在需要時調用此函數,但在代碼繼續執行時在後臺運行它?我只是使用默認圖像,直到正確的圖像變得可用。Python中的背景功能

+0

什麼版本的python? –

回答

70

做這樣的事情:

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

隨即開始,做這樣的事情:通過調用download_thread.isAlive()

import threading 
def my_inline_function(some_args): 
    #do some stuff 
    download_thread = threading.Thread(target=function_that_downloads, args=my_args) 
    download_thread.start() 
    #continue doing stuff 

您可能要檢查線程纔去到其他的事情完成

+0

不錯,簡單!謝謝。 – nicky

+0

解釋器保持打開狀態,直到線程關閉。 (實施例'進口螺紋,時間;等待=拉姆達:time.sleep(2); T = threading.Thread(目標=等待); t.start();印刷( '結束')')。我希望「背景」也意味着分離。 – ThorSummoner

+2

@ThorSummoner線程都包含在同一個進程中。如果你正在尋找一個新的過程,你會想要看看'subprocess'或'multiprocessing' python模塊。 – TorelTwiddler

6

通常,這樣做的方法是使用線程池並排隊下載,這會發出信號,即事件,該任務已完成處理。您可以在Python提供的範圍內執行此操作。

要執行所述操作,我將使用event objectsQueue module

然而,你可以使用一個簡單的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上下文切換時,有其他的「greenlets」運行。對鎖定等的擔心大大減少了,因爲一次只能運行一件事情,但只要在「主要」上下文中執行阻止操作,映像就會繼續下載。

根據多少,你想在後臺做什麼樣的事情,這可以是比基於線程的解決方案更好或更壞;當然,它的規模要大得多(即你可以在後臺做更多的事情),但在目前的情況下這可能不是問題。