python线程
线程模块
Python
标准库提供了两个线程模块:_thread
和threading
。_thread
提供了低级别的、原始的线程以及一个简单的互斥锁,相比threading
模块的功能还是比较有限的。threading
模块是_thread
模块的替代,在实际开发中,绝大多数情况下还是使用高级模块threading
。
创建thread
对象语法如下:
import threading threading.Thread(target=None, name=None, args=())
主要参数说明:
target
是函数名字,需要调用的函数。name
设置线程名字。args
是函数需要的参数,以元祖的形式传入。
主要方法说明:
run()
: 用以表示线程活动的方法。start()
: 启动线程活动。join()
: 等待至线程中止。isAlive()
: 返回线程是否活动的。getName()
: 返回线程名。setName()
: 设置线程名。
函数式创建线程
创建线程的时候,只需要传入一个执行函数和函数的参数即可。下面的例子使用thread
类来产生2
个子线程,然后启动2
个子线程并等待其结束,
#!/usr/bin/python # -*- coding: UTF-8 -*- import threading import time,random,math def print_num(idx): for num in range(idx): print("{0}\tnum={1}".format(threading.current_thread().getName(), num)) delay = math.ceil(random.random() * 2) time.sleep(delay) if __name__ == '__main__': th1 = threading.Thread(target=print_num, args=(2,), name="test1") th2 = threading.Thread(target=print_num, args=(3,), name="test2") th1.start() th2.start() th1.join() th2.join() print("{0} over".format(threading.current_thread().getName()))
运行结果如下:
$ python thread1.py test1 num=0 test2 num=0 test1 num=1 test2 num=1 test2 num=2 MainThread over
运行脚本默认会启动一个线程,把该线程称为主线程,主线程又启动新的线程。Python
的threading
模块有个current_thread()
函数,它将返回当前线程的实例,可以获得运行线程名字,代码如下:
threading.current_thread().getName()
启动一个线程就是把一个函数和参数传入并创建thread
实例,然后调用start()
开始执行:
th1 = threading.Thread(target=print_num, args=(2,), name="test1" ) th1.start()
从返回结果可以看出主线程的名字叫MainThread
,子线程的名字在创建时指定。如果没有给线程起名字,Python
就自动给线程命名为Thread-1
、Thread-2
等等。
创建线程类
通过继承thread
类,并重写thread
类的run()
方法,在run()
方法中定义具体要执行的任务。在thread
类中,提供了一个start()
方法用于启动新线程,线程启动后会自动调用run()
方法。
#!/usr/bin/python # -*- coding: UTF-8 -*- import threading import time,random,math class MutliThread(threading.Thread): def __init__(self, threadName, num): threading.Thread.__init__(self) self.name = threadName self.num = num def run(self): for i in range(self.num): print("{0} i={1}".format(threading.current_thread().getName(), i)) delay = math.ceil(random.random() * 2) time.sleep(delay) if __name__ == '__main__': thr1 = MutliThread("test1", 3) thr2 = MutliThread("test2", 2) thr1.start() thr2.start() thr1.join() thr2.join() print("{0} over".format(threading.current_thread().getName()))
运行结果如下:
$ python thread2.py test1 i=0 test2 i=0 test1 i=1 test2 i=1 test1 i=2 MainThread over
从返回结果可以看出,通过创建thread
类来产生2
个线程对象thr1
和thr2
,重写thread
类的run()
函数,把业务逻辑放入其中,通过调用线程对象的start()
方法启动线程。通过调用线程对象的join()
函数,等待该线程完成。
守护线程
在线程模块中,使用子线程对象用到join()
函数,主线程需要依赖子线程执行完毕后才继续执行。如果不使用join()
函数,主线程和子线程是并行运行的,没有依赖关系。
在多线程开发中,如果子线程设定为守护线程,守护线程会等待主线程运行完毕后被销毁。一个主线程可以设置多个守护线程,守护线程运行的前提是主线程必须存在,如果主线程不存在了,守护线程会被销毁。
以下例子创建了1
个主线程和3
个子线程,让主线程和子线程并行执行,代码如下:
#!/usr/bin/python # -*- coding: UTF-8 -*- import threading, time def run(taskName): print("task:", taskName) time.sleep(2) print("{0} over".format(taskName)) if __name__ == '__main__': start_time = time.time() for i in range(3): thr = threading.Thread(target=run, args=("task-{0}".format(i),)) thr.start() print("{0} over,thread_num={1}".format(threading.current_thread().getName(), threading.active_count())) print("cost time:", time.time() - start_time)
运行结果如下:
$ python thread3.py ('task:', 'task-0') ('task:', 'task-1') ('task:', 'task-2') MainThread over,thread_num=4 ('cost time:', 0.0011091232299804688) task-0 over task-1 over task-2 over
从返回结果可以看出,当前的线程个数是4
,主线程执行完毕后,等待子线程执行完毕,程序才会退出。
在以上例子的基础上,使用线程对象的setDaemon(True)
函数把所有的子线程都设置为守护线程。子线程变成守护线程后,只要主线程执行完毕,程序不管子线程有没有执行完毕,程序都会退出。
#!/usr/bin/python # -*- coding: UTF-8 -*- import threading, time def run(taskName): print("task:", taskName) time.sleep(2) print("{0} over".format(taskName)) if __name__ == '__main__': start_time = time.time() for i in range(3): thr = threading.Thread(target=run, args=("task-{0}".format(i),)) thr.setDaemon(True) thr.start() thrName = threading.current_thread().getName() thrCount = threading.active_count() print("{0} over,thread_num={1}".format(thrName, thrCount)) print("cost time:", time.time() - start_time)
运行结果如下:
$ python thread4.py ('task:', 'task-0') ('task:', 'task-1') ('task:', 'task-2') MainThread over,thread_num=4 ('cost time:', 0.0005180835723876953)
从返回结果可以看出,主线程执行完毕后,程序不会等待守护线程执行完毕就退出了。设置线程对象为守护线程,一定要在线程对象调用start()
函数前设置。