概述
本节主要介绍python线程的使用,与对进程的使用类似
线程的生命周期
五种状态:
- 新建(new): 新创建的线程经过初始化后,进入就绪(Runnable)状态
- 就绪(Runnable):等待线程调度。调度后进入运行状态
- 运行(Running):当就绪的线程被调度并获得CPU时,便进入运行状态
- 阻塞(Blocked):暂停运行,解除阻塞后进入Runnable状态重新等待调度
- 死亡(Dead):线程方法执行完毕返回或者异常终止
从“运行”进入“阻塞”(Blocked):
- 同步:线程中获取同步锁,但是资源已经被其他线程锁定时,进入Locked状态,直到该资源可获取(获取的顺序由Lock队列控制)
- 睡眠:线程运行sleep()或join()方法后,线程进入Sleeping状态。区别在于sleep等待固定的时间,而join是等待子线程执行完。当然join也可以指定一个“超时时间”。从语义上来说,如果两个线程a,b, 在a中调用b.join(),相当于合并(join)成一个线程。最常见的情况是在主线程中join所有的子线程。
- 等待:线程中执行wait()方法后,线程进入Waiting状态,等待其他线程的通知(notify)。
感性认识
普通方式:
import os
while True:
print('pid=%d'%os.getpid())
多线程方式:
先实现一个最简单的多线程程序,运行查看结果
#coding=utf-8
from threading import Thread
import time
import os
def task1():
#任务1
while True:
print('1')
time.sleep(1)
def task2():
#任务2
while True:
print('2')
time.sleep(1)
print('pid=%d'%os.getpid())
#创建2个线程,与Process类似
t=Thread(target=task1)
t2=Thread(target=task2)
#启动线程
t.start()
t2.start()
print('代码结束')
查看该进程的线程数量:
该进程有3个线程,1个主线程,2个由主线程创建的子线程
python多线程与多进程的区别
- 只有一个进程,该进程的线程数有多个
- 不需要重新读取py文件,只是调用函数
Thread类使用说明
导入模块
import threading
或者
from threading import Thread
创建对象
语法:
Thread(self, group=None, target=None, name=None,args=(), kwargs=None, *, daemon=None)
参数说明:
- group:一般不使用
- target:表示调用对象
- name:为别名
- args:表示调用对象的位置参数元组
- kwargs:表示调用对象的关键字参数字典
常用属性
- name:当前线程别名,在实例化时通过参数name指定,默认为Thread=N,N为从1开始递增的整数
常用方法
start():启动线程实例
is_alive():判断线程实例是否还在执行,返回布尔值
join([timeout]):参见
run():参见 python-Thread子类创建进程
threading模块使用说明
- threading.current_thread():返回当前线程对象
- threading.main_thread():返回主线程对象
- threading.enumerate():返回当前存在的所有线程对象的列表
- threading.active_count(): 返回当前存活的线程对象的数量。通过计算len(threading.enumerate())长度而来
Thread创建线程
#coding=utf-8
from threading import Thread,current_thread,active_count,main_thread
import time,os
def task():
ct=current_thread()
mt=main_thread()
print('task()---子线程开始----当前线程名称:%s,主线程名称:%s'%(ct.name,mt.name))
time.sleep(1)
# time.sleep(4)
print('task()---子线程结束----当前线程名称:%s,主线程名称:%s'%(ct.name,mt.name))
if __name__ == "__main__":
print('pid=%s'%os.getpid())
t=Thread(target=task,name='子线程')
t.start()
print('main()---主线程名称:%s'%current_thread().name)
print('main()---线程活动总数:%d'%active_count())
time.sleep(3)
print('main()---线程活动总数:%d'%active_count())
print('最后一行代码')
执行结果:
pid=6804
task()---子线程开始----当前线程名称:子线程,主线程名称:MainThread
main()---主线程名称:MainThread
main()---线程活动总数:2
task()---子线程结束----当前线程名称:子线程,主线程名称:MainThread
main()---线程活动总数:1
最后一行代码
结论:
创建并启动子线程后,主线程仍然继续执行
注释掉11行代码,释放12行代码
执行结果如下:
pid=9152
task()---子线程开始----当前线程名称:子线程,主线程名称:MainThread
main()---主线程名称:MainThread
main()---线程活动总数:2
main()---线程活动总数:2
最后一行代码
task()---子线程结束----当前线程名称:子线程,主线程名称:MainThread
结论:
子线程运行结束后,进程才会结束
守护线程
def task():
print('子线程-启动')
time.sleep(1)
print('子线程-结束')
def task2():
print('守护线程-启动')
time.sleep(3)
print('守护线程-结束')
if __name__ == "__main__":
print('pid=%s'%os.getpid())
t=Thread(target=task)
t2=Thread(target=task2,daemon=True)
t.start()
t2.start()
print('最后一行代码')
结果:
pid=8208
子线程-启动
守护线程-启动
最后一行代码
子线程-结束
结论:
当只剩下守护线程时,进程结束



