目录结构
一、进程
二、线程
1. 多线程实现
2. 主线程和子线程
3. 线程锁(互斥锁)
4. 多线程案例:多个窗口并行售票
5. 全局解释器锁(GIL)
三、多进程
一、进程
进程:描述程序文件从运行开始到结束的过程
进程有三个状态:就绪、运行、阻塞
- 就绪态:获取了除CPU以外的所有资源,只要处理器分配资源就可马上执行。
- 运行态:获得了处理器分配的资源,程序开始执行。
- 阻塞态:当程序条件不够时,需要等待条件满足时侯才能执行。如等待i/o操作时,此刻的状态就叫阻塞态。
二、线程
- 线程:一个进程可以包含多个线程(≥1个线程),进程作为分配资源的基本单位;线程作为进程下更小的划分单位,需要依赖于进程而执行,线程可利用进程所拥有的资源
- 多线程:一个应用程序中有多个执行部分可同时执行,同一时间完成多项任务,以提高资源使用效率。如:QQ软件可同时实现播放音效、消息发送等功能
1. 多线程实现
Python标准库提供的2个模块:_thread(低级模块)、threading(高级模块,已对_thread进行封装)
启动一个线程:创建线程+执行线程。把一个函数传入并创建Thread实例,然后调用start()开始执行
案例:多个线程并行执行;同时(同一个时间段)执行多个线程
PS:多线程执行时的"同时"非同一时刻,而是同一时间段内
multiThread.py
import threading
import time
# 定义执行线程的方法
def run(name):
print(name,"线程执行")
time.sleep(3)
# 创建2个线程
# target传入调用的方法,args传入对应方法的参数(每个参数后需要加上',')
t1=threading.Thread(target=run,args=("t001",))
t2=threading.Thread(target=run,args=("t002",))
t3=threading.Thread(target=run,args=("t003",))
print("---执行开始---\n")
# 启动线程(执行)
t1.start()
t2.start()
t3.start()
print("\n---执行完毕---")
执行结果:
![](https://img.haomeiwen.com/i4866277/8688cf74873b7dad.png)
以上,3个线程并行执行,花费的总时间是3.4s(包含3s的延迟时间),实际执行花费0.4s
2. 主线程和子线程
- 主线程:程序执行时,程序本身就是一个线程,作为主线程
- 子线程:程序中所手动创建的线程,作为子线程
PS:
①程序无设置的情况下,主线程不会等待子线程执行完毕才执行,而是直接执行
②若程序中采用线程对象调用join()方法,则可设置先执行完成子线程,然后才执行主线程
以上multiThread.py程序中的print("\n---执行完毕---")
属于主线程中的一部分,t1.start()
属于子线程,子线程开始执行后,未执行完成3s等待,主线程就会先打印 "---执行完毕---",然后3s后程序才会真正执行完成
以下采用线程对象调用join()方法,实现先执行完成子线程(包括等待3s),然后才会执行主线程中的print("\n---执行完毕---")
在代码中新增:
# 等待子线程执行完成之后再执行主线程内容
t1.join()
t2.join()
t3.join()
3. 线程锁(互斥锁)
线程锁:解决某个线程执行到一半又去执行另一个线程,导致的多线程执行产生错乱。具体表现为:多线程执行过程中,将每个子线程执行的代码作为一个完整的单元进行锁定,执行某个单元未完成时不跳出执行,执行完成一个完整的单元即进行解锁释放。
代码实现:
threadLock.py
import threading
# 创建一个线程锁
lock=threading.Lock()
num=10 # 当前需要执行的线程数
def run(name):
lock.acquire() # 设置锁
global num # 设置num为全局变量
num=num-1
print("线程",name,"执行了,目前剩余执行的线程数:",num)
lock.release() # 释放锁
# 创建并启动线程
for i in range(10):
t=threading.Thread(target=run,args=(i+1,))
t.start()
执行结果:
![](https://img.haomeiwen.com/i4866277/affed93f9f3353c8.png)
若未加线程锁,则会出现执行和统计错乱,如下:
![](https://img.haomeiwen.com/i4866277/5dd83a5e3ab33102.png)
4. 多线程案例:多个窗口并行售票
案例:利用Python多线程机制,模拟多窗口(对应多个线程)并行进行售票,所有票售完为止
sale.py
import threading
lock=threading.Lock()
num=100
# 定义售票方法
def sale(name):
lock.acquire()
global num
if num>=1:
num=num-1
print(name,"卖出一张票,当前余票数:",num)
lock.release()
# 售票窗口(与多线程中线程数目对应)
while True:
if num>=1:
t1=threading.Thread(target=sale,args=("A窗口",))
t2=threading.Thread(target=sale,args=("B窗口",))
t3=threading.Thread(target=sale,args=("C窗口",))
t4=threading.Thread(target=sale,args=("D窗口",))
t5=threading.Thread(target=sale,args=("E窗口",))
t1.start()
t2.start()
t3.start()
t4.start()
t5.start()
else:
print("票已售罄!")
break
执行结果:
![](https://img.haomeiwen.com/i4866277/4078d1a7ba17b1d5.png)
5. 全局解释器锁(GIL)
GIL(Global Interpreter Lock)使得在Python程序中,不管CPU核心数有多少,同一时间点只能执行一个线程。缺点:本意是为了实现数据安全,但CPU资源的浪费,发挥不了多核的优势,程序执行效率低,弊大于利
三、多进程
使用多进程解决GIL所造成的问题,多进程可实现同一时间点多个任务并行
multiProcess.py
from multiprocessing import Process
import time
def run(name):
print(name,"进程执行")
time.sleep(3)
if __name__=='__main__': # Windows系统中需要写入到main方法中
# 创建进程
p1=Process(target=run,args=("pr1",))
p2=Process(target=run,args=("pr2",))
p3=Process(target=run,args=("pr3",))
p4=Process(target=run,args=("pr4",))
p5=Process(target=run,args=("pr5",))
# 启动线程
p1.start()
p2.start()
p3.start()
p4.start()
p5.start()
![](https://img.haomeiwen.com/i4866277/91072860c2d88544.png)
网友评论