2011-08-23 34 views
48

Tôi có một tập lệnh Python đôi khi hiển thị hình ảnh cho người dùng. Những hình ảnh có thể, đôi khi, khá lớn, và chúng được tái sử dụng thường xuyên. Hiển thị chúng không quan trọng, nhưng hiển thị thông điệp liên kết với chúng là. Tôi có một chức năng tải hình ảnh cần thiết và lưu nó cục bộ. Hiện tại, nó chạy nội dòng với mã hiển thị thông báo cho người dùng, nhưng đôi khi có thể mất hơn 10 giây cho hình ảnh không phải cục bộ. Có cách nào tôi có thể gọi chức năng này khi nó cần thiết, nhưng chạy nó trong nền trong khi mã tiếp tục thực hiện? Tôi sẽ chỉ sử dụng hình ảnh mặc định cho đến khi hình ảnh chính xác có sẵn.chức năng nền trong Python

+0

phiên bản nào của python? –

Trả lời

70

Làm như thế này:

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

sau đó inline, làm một cái gì đó như thế này:

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 

Bạn có thể muốn kiểm tra xem các chủ đề đã kết thúc trước khi đi vào những thứ khác bằng cách gọi download_thread.isAlive()

+0

Đẹp và đơn giản! Cảm ơn. – nicky

+0

Thông dịch viên vẫn mở cho đến khi luồng đóng. (ví dụ 'nhập luồng, thời gian; chờ = lambda: time.sleep (2); t = threading.Thread (target = wait); t.start(); print ('end')'). Tôi đã hy vọng "nền" ngụ ý tách ra là tốt. – ThorSummoner

+2

@ThorSummoner Chủ đề đều nằm trong cùng một quy trình. Nếu bạn đang tìm kiếm để sinh ra một quy trình mới, bạn sẽ muốn xem xét các mô-đun python 'subprocess' hoặc' multiprocessing' thay thế. – TorelTwiddler

6

Thông thường cách để làm điều này sẽ sử dụng một nhóm luồng và xếp hàng tải xuống, sẽ phát ra tín hiệu, a.k.a một sự kiện, nhiệm vụ đó đã xử lý xong. Bạn có thể làm điều này trong phạm vi của Python cung cấp.

Để thực hiện các tác vụ đã nêu, tôi sẽ sử dụng event objectsQueue module.

Tuy nhiên, một cuộc biểu tình nhanh chóng và dơ bẩn của những gì bạn có thể làm bằng cách sử dụng threading.Thread thực hiện đơn giản có thể được nhìn thấy dưới đây:

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

Nó có lẽ sẽ làm cho tinh thần để không thăm dò ý kiến ​​như tôi đang làm ở trên. Trong trường hợp đó, tôi sẽ thay đổi mã này:

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 

Lưu ý rằng không có cờ daemon nào được đặt ở đây.

3

Tôi thích sử dụng gevent cho loại điều sau:

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

Mọi thứ đều chạy trong một chuỗi, nhưng bất cứ khi nào một khối hoạt động hạt nhân, gevent chuyển đổi ngữ cảnh khi có "greenlets" khác đang chạy. Những lo lắng về khóa, vv bị giảm nhiều, vì chỉ có một thứ chạy cùng một lúc, nhưng hình ảnh sẽ tiếp tục tải xuống bất cứ khi nào một hoạt động chặn thực hiện trong ngữ cảnh "chính".

Tùy thuộc vào mức độ và loại điều bạn muốn làm trong nền, điều này có thể tốt hơn hoặc tệ hơn các giải pháp dựa trên luồng; chắc chắn, nó có khả năng mở rộng hơn nhiều (tức là bạn có thể làm nhiều việc hơn trong nền), nhưng điều đó có thể không phải là mối quan tâm trong tình hình hiện tại.