22 January 2018

最简单的多线程实现

通过为 Thread 传入 target 参数可以启动一个最简单的线程

import time
from threading import Thread

def thread_worker():
    for i in xrange(3):
        time.sleep(2)
        print 'threaded worker at %d' % i


if __name__ == '__main__':
    t = Thread(target=thread_worker)
    t.start()
    time.sleep(0.5)
    for i in xrange(3):
        time.sleep(1)
        print 'main thread at %d' % i

从输出结果可以看到,两个线程互不干扰地各自执行

$ python test_thread.py 
main thread at 0
threaded worker at 0
main thread at 1
main thread at 2
threaded worker at 1
threaded worker at 2

如果有多个线程,可以对线程进行命名。 target 函数也可以传入相应参数

import time
import threading
from threading import Thread

def thread_worker(arg):
    for i in xrange(3):
        time.sleep(2)
        print 'threaded worker %s with arg %s at %d' % (threading.currentThread().getName(), arg, i)

def thread_worker_2(arg):
    print 'threaded worker %s with arg %s' % (threading.currentThread().getName(), arg)

if __name__ == '__main__':
    t = Thread(name='Thread1', target=thread_worker, args=('arg1',))
    t2 = Thread(name='Thread2', target=thread_worker_2, args=('arg2',))
    t.start()
    t2.start()
    time.sleep(0.5)
    for i in xrange(3):
        time.sleep(1)
        print 'main thread %s at %d' % (threading.currentThread().getName(), i)
$ python test_thread.py 
threaded worker Thread2 with arg arg2
main thread MainThread at 0
threaded worker Thread1 with arg arg1 at 0
main thread MainThread at 1
main thread MainThread at 2
threaded worker Thread1 with arg arg1 at 1
threaded worker Thread1 with arg arg1 at 2

Thread对象

对于更复杂的应用场景,通常通过构造 Thread 对象的方法来实现。例如以下代码可以实现和上一个例子完全等价的效果

import time
import threading
from threading import Thread


class worker1(Thread):

    def __init__(self, name, arg):
        self.arg = arg
        threading.Thread.__init__(self, name=name)

    def run(self):
        for i in xrange(3):
            time.sleep(2)
            print 'threaded worker %s with arg %s at %d' % (threading.currentThread().getName(), self.arg, i)


class worker2(Thread):

    def __init__(self, name, arg):
        self.arg = arg
        threading.Thread.__init__(self, name=name)

    def run(self):
        print 'threaded worker %s with arg %s' % (threading.currentThread().getName(), self.arg)


if __name__ == '__main__':
    t = worker1(name='Thread1', arg='arg1')
    t2 = worker2(name='Thread2', arg='arg2')
    t.start()
    t2.start()
    time.sleep(0.5)
    for i in xrange(3):
        time.sleep(1)
        print 'main thread %s at %d' % (threading.currentThread().getName(), i)

输出将和之前的例子完全一致。

显然通过构造 Thread 实例并定义 run() 函数,可以实现更复杂的功能。例如一个GUI程序在主程序显示用户界面,同时通过另外的线程周期性的刷新数据并据此更新用户界面状态

daemon vs non-daemon

上面的例子中,可以看到主线程结束后, Thread1 这个线程仍在运行。大部分情况下,这都不是我们希望有的情况,因为极有可能这个非主线程会“跑飞”了。如果需要在主线程结束后自动结束所有其他线程,只要给新开的线程设置 daemon 属性即可。

import time
import threading
from threading import Thread


class worker1(Thread):

    def __init__(self, name, arg):
        self.arg = arg
        threading.Thread.__init__(self, name=name)

    def run(self):
        for i in xrange(3):
            time.sleep(2)
            print 'threaded worker %s with arg %s at %d' % (threading.currentThread().getName(), self.arg, i)


class worker2(Thread):

    def __init__(self, name, arg):
        self.arg = arg
        threading.Thread.__init__(self, name=name)

    def run(self):
        print 'threaded worker %s with arg %s' % (threading.currentThread().getName(), self.arg)


if __name__ == '__main__':
    # t = Thread(name='Thread1', target=thread_worker, args=('arg1',))
    # t2 = Thread(name='Thread2', target=thread_worker_2, args=('arg2',))
    t = worker1(name='Thrad1', arg='arg1')
    t.daemon = True
    t2 = worker2(name='Thread2', arg='arg2')
    t.start()
    t2.start()
    time.sleep(0.5)
    for i in xrange(3):
        time.sleep(1)
        print 'main thread %s at %d' % (threading.currentThread().getName(), i)

可以看到主线程结束后 daemon 线程也结束了

$ python test_thread.py 
threaded worker Thread2 with arg arg2
main thread MainThread at 0
threaded worker Thread1 with arg arg1 at 0
main thread MainThread at 1
main thread MainThread at 2


blog comments powered by Disqus