Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

background function in Python

I've got a Python script that sometimes displays images to the user. The images can, at times, be quite large, and they are reused often. Displaying them is not critical, but displaying the message associated with them is. I've got a function that downloads the image needed and saves it locally. Right now it's run inline with the code that displays a message to the user, but that can sometimes take over 10 seconds for non-local images. Is there a way I could call this function when it's needed, but run it in the background while the code continues to execute? I would just use a default image until the correct one becomes available.

like image 905
Dan Hlavenka Avatar asked Aug 23 '11 22:08

Dan Hlavenka


People also ask

How do I run a Python subprocess in the background?

To start a background process in Python, we call subprocess. Popen . to call subprocess. Popen with a list with the command and command arguments to run the command in the background.


2 Answers

Do something like this:

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

then inline, do something like this:

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 

You may want to check if the thread has finished before going on to other things by calling download_thread.isAlive()

like image 161
TorelTwiddler Avatar answered Oct 18 '22 02:10

TorelTwiddler


Typically the way to do this would be to use a thread pool and queue downloads which would issue a signal, a.k.a an event, when that task has finished processing. You can do this within the scope of the threading module Python provides.

To perform said actions, I would use event objects and the Queue module.

However, a quick and dirty demonstration of what you can do using a simple threading.Thread implementation can be seen below:

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

It would probably make sense to not poll like I'm doing above. In which case, I would change the code to this:

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 

Notice that there's no daemon flag set here.

like image 42
Mahmoud Abdelkader Avatar answered Oct 18 '22 00:10

Mahmoud Abdelkader