线程
什么是线程
前面说过了进程,进程最少有一个线程。进程是计算机中最小的资源分配单位,线程是cpu调度的最小单位。
什么意思呢?简单来说就是你要运行的一个程序,进程是一个代码仓库给线程分配资源的,要想让程序运行起来,cpu就找到线程让线程去工作。
再打个比方,你老板要实现一个功能,需要你来完成,总不可能说你的手去给我写这个功能吧。只能命令你让你给你的手分配工作去完成。大概就这种情况。
进程和线程的关系
线程的特点
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
线程和cpython
理论知识
全局解释器锁GIL
Python代码的执行由Python虚拟机(也叫解释器主循环)来控制。Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行。虽然 Python 解释器中可以“运行”多个线程,但在任意时刻只有一个线程在解释器中运行。
对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。
在多线程环境中,Python 虚拟机按以下方式执行:
a、设置 GIL;
b、切换到一个线程去运行;
c、运行指定数量的字节码指令或者线程主动让出控制(可以调用 time.sleep(0));
d、把线程设置为睡眠状态;
e、解锁 GIL;
d、再次重复以上所有步骤。
在调用外部代码(如 C/C++扩展函数)的时候,GIL将会被锁定,直到这个函数结束为止(由于在这期间没有Python的字节码被运行,所以不会做线程切换)编写扩展的程序员可以主动解锁GIL。
python线程模块的选择
Python提供了几个用于多线程编程的模块,包括thread、threading和Queue等。thread和threading模块允许程序员创建和管理线程。thread模块提供了基本的线程和锁的支持,threading提供了更高级别、功能更强的线程管理的功能。Queue模块允许用户创建一个可以用于多个线程之间共享数据的队列数据结构。
避免使用thread模块,因为更高级别的threading模块更为先进,对线程的支持更为完善,而且使用thread模块里的属性有可能会与threading出现冲突;其次低级别的thread模块的同步原语很少(实际上只有一个),而threading模块则有很多;再者,thread模块中当主线程结束时,所有的线程都会被强制结束掉,没有警告也不会有正常的清除工作,至少threading模块能确保重要的子线程退出后进程才退出。
thread模块不支持守护线程,当主线程退出时,所有的子线程不论它们是否还在工作,都会被强行退出。而threading模块支持守护线程,守护线程一般是一个等待客户请求的服务器,如果没有客户提出请求它就在那等着,如果设定一个线程为守护线程,就表示这个线程是不重要的,在进程退出的时候,不用等待这个线程退出。
threading模块
multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性,因而不再详细介绍(官方链接)
线程的创建Threading.Thread类
线程的创建
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import os import time from threading import Thread # multiprocessing 是完全仿照这threading的类写的 def func(): print('start son thread') time.sleep(1) print('end son thread',os.getpid()) # 启动线程 start 线程可以不用写 if ...main... Thread(target=func).start() print('start',os.getpid()) time.sleep(0.5) print('end',os.getpid())
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import os import time from threading import Thread # multiprocessing 是完全仿照这threading的类写的 class Mythread(Thread): def __init__(self,name): super().__init__() self.name = name def run(self): print('%s hello thread'%self.name,self.ident) # self.ident 线程号 # 启动线程 start t = Mythread('wuye') t.start() print('主线程',t.ident)
多线程的创建
# 主线程什么时候结束?等待所有子线程结束之后才结束 # 主线程如果结束了,主进程也就结束了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def func(i): print('start son thread',i) time.sleep(1) print('end son thread',i,os.getpid()) for i in range(10): Thread(target=func,args=(i,)).start() print('main')
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# join方法 阻塞 直到子线程执行结束 def func(i): print('start son thread',i) time.sleep(1) print('end son thread',i,os.getpid()) t_l = [] for i in range(10): t = Thread(target=func,args=(i,)) t.start() t_l.append(t) for t in t_l:t.join() print('子线程执行完毕')
Thread类的其它方法
Thread实例对象的方法 # isAlive(): 返回线程是否活动的。 # getName(): 返回线程名。 # setName(): 设置线程名。 threading模块提供的一些方法: # threading.currentThread(): 返回当前的线程变量。 # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。 # threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from threading import current_thread,enumerate,active_count def func(i): t = current_thread() print('start son thread',i,t.ident) time.sleep(1) print('end son thread',i,os.getpid()) t = Thread(target=func,args=(1,)) t.start() print(t.ident) print(current_thread().ident) # 在哪一个线程里,current_thread()得到的就是这个当前线程的信息 print(enumerate()) # enumerate 检测存活的线程类,返回成列表 print(active_count()) # =====len(enumerate())
守护线程
# 守护线程一直等到所有的非守护线程都结束之后才结束 # 当主线程代码执行完毕守护线程也随之结束 # 除了守护了主线程的代码之外也会守护子线程
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import time from threading import Thread def son1(): while True: time.sleep(0.5) print('in son1') def son2(): for i in range(5): time.sleep(1) print('in son2') t =Thread(target=son1) t.daemon = True t.start() Thread(target=son2).start() time.sleep(3)
小测试
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def func(a,b): c = a+b import time from multiprocessing import Process from threading import Thread if __name__ == '__main__': start = time.time() p_l = [] for i in range(100): p = Process(target=func,args=(i,i*2)) p.start() p_l.append(p) for p in p_l:p.join() print('process :',time.time() - start) start = time.time() p_l = [] for i in range(100): p = Thread(target=func, args=(i, i * 2)) p.start() p_l.append(p) for p in p_l: p.join() print('thread :',time.time() - start)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from threading import Thread n = 100 def func(): global n # 不要在子线程里随便修改全局变量 n-=1 t_l = [] for i in range(100): t = Thread(target=func) t_l.append(t) t.start() for t in t_l:t.join() print(n)