2011-08-23 71 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”运行。对锁定等的担心大大减少了,因为一次只能运行一件事情,但只要在“主要”上下文中执行阻止操作,映像就会继续下载。

根据多少,你想在后台做什么样的事情,这可以是比基于线程的解决方案更好或更坏;当然,它的规模要大得多(即你可以在后台做更多的事情),但在目前的情况下这可能不是问题。