Welcome, guest | Sign In | My Account | Store | Cart

A decorator, that makes it easy to switch between the mainthread and background threads.

Python, 48 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import threading
from Queue import Queue

# Set up a queue for tasks to be run on the main thread.
# Most UI toolkits as glib contains functions to push task this way.
Q = Queue()
def idle_add(a,b):
	Q.put((a,b))

def async_int(gen):
    try: gen.next()
    except StopIteration: return
    def do():
        try: gen.next()
        except StopIteration: return
        idle_add(async_int, gen)
    threading.Thread(target=do).start()

def async(func):
    return lambda *a,**kw: async_int(func(*a,**kw))

@async
def test():
    # We start in the main thread
    print "1 %s" % threading.currentThread()
    yield
    
    # This part is run in a seperate thread, not blocking the main thread
    print "2 %s" % threading.currentThread()
    yield
    
    # Now we are back in the main thread
    print "3 %s" % threading.currentThread()
    yield
    
    # And in another background thread
    print "4 %s" % threading.currentThread()
    yield
    
    # And we keep all internal variables between the threads!
    print "5 %s" % threading.currentThread()

if __name__ == "__main__":
    test()
    
    while True:
        a,b = Q.get()
        a(b)

In GUI programs you'll often want switch between the main thread (for updating the gui) and background threads (for work).

Imagine you have a callback function which first grabs some data from the UI, then does some IO, and finally updates the UI with the result. If you don't want the UI to freeze temporarily, you'll have to put the IO in a background thread. (I know there are other libraries for background io, but it could be any task, that requires to be off the main thread)

Apple has made it easy to push tasks off the main thread with their GCD: http://en.wikipedia.org/wiki/Grand_Central_Dispatch#Examples . The GCD uses inline functions/blocks. Unfortunatly Python doesn't feature multiline inline functions, so python programmers would typically split the imagined callback function in three: before, async and after.

I personally find this 'splitting' destructive, so here is a way to keep things together.

The Queue, whileloop and idle_add function are just dummy replacements for the ones you find in your gui library.