之前对多线程的概念有了基本的了解,包括线程进程,锁,信号量等。python多线程基本概念
线程模块
python 提供了多个模块来支持多线程编程,基础的有thread,threading,Queue等,thread和threading可以创建和管理多线程。thread支持基本的线程管理,不过threading更加全面和安全的线程管理。而Queue可以创建一个数据队列,进行线程共享。
在这里,我们不选用原始的thread模块,有很多的原因,thread支持的同步原语只有一个,threading支持更多。而且还有一个原因是thread模块对线程的退出没有安全的控制,就是说一般我们的主线程退出以后,其他线程应该有保护,而thread对此没有措施,子线程会直接强制退出,这样就可能造成数据丢失错误等意外。而threading模块就可以自定义让那些重要的线程可以在主程序退出前已经结束。就是守护线程的概念。
threading模块
守护线程
threading模块支持守护线程,守护线程代表的意思是这个线程是不重要的,也就是主线程是不会等待它执行完才推出的。讲一个线程设置成守护线程的方法就是在线程启动前将守护标记设置为真,在threading模块里就是设置thread.daemon=True
,这样守护线程就设置好了,主线程就不会等他它了,也就是它结不结束了主线程都不会理他的意见了。
threading的属性和方法
Thread类属性
- name:线程名
- ident:线程的标识符
- daemon:表示是否是守护线程
Thread类方法
- init(group=None,target=None,name=None,args=(),kwargs={},verbose=None,daemon=None): 实例化一个线程对象,有可调用的target参数可其余的args和kwargs参数 支持传递name和group参数,不过group参数还未实现。verbose参数是接受的。daemon值由属性thread.daemon值设置
- start():开始执行这个线程。
- run():定义想想的功能,也就是你要用这个线程作什么,你就将你要做的事情重写这个方法。
- join(timeout=None):挂起直到启动的线程结束,或者设置了timeout。
- getName():返回线程名
- setName(name):设置线程名
- isAlive/is_alive():布尔标志表示线程是否处于进行中
- isDaemon():返回线程是否是守护线程
- setDaemon(daemonic):设置线程是都为守护线程。线程开始前调用有效
一般使用Thread类有三种方式:
- 创建Thread的实例,传给它一个函数。
- 创建Thread的实例,传给它一个可调用的类的实例。
- 派生Thread的子类,并创建子类的实例。
一般选用第一种和第三种,而第三种比较面向对象。
threading模块还提供了另外一些函数
- activeCount/active_count():当前活动的Thread个数
- current Thread()/current_thread()返回当前Thread对象
- enumerate():返回当前活动的Thread对象
……
举个栗子
选用第三种方式来举个简单的例子:
这是派生的Thread的子类,用传入函数这样简单一点的方式
# mythread.py
import threading
from time import ctime
class MyThread(threading.Thread):
def __init__(self, func, args, name=''):
threading.Thread.__init__(self)
self.name = name # 线程的名字
self.args = args # 传入供有关执行的函数的参数
self.func = func # 传入要执行的函数
def get_result(self):
return self.res # 返回实例结果
def run(self):
print('starting', self.name, 'at:', ctime()) # 输出执行的线程开始的时间
self.res = self.func(*self.args)
print(self.name, 'finished at:', ctime()) # 输出执行的线程结束的时间
实现多线程运行的代码:
from test_4_6.mythread import MyThread # 自定义的线程类
from time import ctime, sleep
def fib(x):
# 斐波那契数列
sleep(0.005) # 延长执行时间
if x < 2:
return 1
return fib(x - 2) + fib(x - 1)
def fac(x):
# 递归数的阶乘
sleep(0.1)
if x < 2:
return 1
return x * fac(x - 1)
def sum1(x):
# 求1到某数的和
sleep(0.1)
if x < 2:
return 1
return x + sum1(x - 1)
funcs = [fib, fac, sum1]
n = 12
def main():
# 先不用多线程,按正常的顺序执行的方式
nfuncs = range(len(funcs)) # 产生随机数执行函数
print('*** SINGLE THREAD')
for i in nfuncs:
print('starting ', funcs[i].__name__, 'at:', ctime()) # 当前运行的线程开始时间
print(funcs[i](n)) # 运行结果
print(funcs[i].__name__, 'finished at:', ctime()) # 执行结束时间
print("*** MULTIPLE THREADS")
threads = [] # 产生的线程对象列表
for i in nfuncs:
t = MyThread(funcs[i], (n,), funcs[i].__name__)
threads.append(t) # 产生线程,此时线程并没有开始执行,并加入到线程列表中让他们同时启动
for i in nfuncs:
threads[i].start() # 启动线程
for i in nfuncs:
threads[i].join()
print(threads[i].get_result()) # 等待线程结束并输出结果
# 不过join()函数可以不使用,我们没有设置守护线程,所以默认有线程保护。
print('all DONE!')
if __name__ == '__main__':
main()
结果:
*** SINGLE THREAD
starting fib at: Fri Aug 25 11:27:25 2017
233
fib finished at: Fri Aug 25 11:27:29 2017
starting fac at: Fri Aug 25 11:27:29 2017
479001600
fac finished at: Fri Aug 25 11:27:30 2017
starting sum1 at: Fri Aug 25 11:27:30 2017
78
sum1 finished at: Fri Aug 25 11:27:31 2017
*** MULTIPLE THREADS
starting fib at: Fri Aug 25 11:27:31 2017
starting fac at: Fri Aug 25 11:27:31 2017
starting sum1 at: Fri Aug 25 11:27:31 2017
sum1 finished at: Fri Aug 25 11:27:32 2017
fac finished at: Fri Aug 25 11:27:32 2017
fib finished at: Fri Aug 25 11:27:34 2017
233
479001600
78
all DONE!
Process finished with exit code 0