python 多线程 多进程
目录
https://www.byhy.net/py/lang/extra/multi_thread/
进程和线程的概念
我们写的python程序,右键运行起来,就称之为一个进程。可以在windows任务管理器查看到
当Python解释器程序运行起来(成为一个进程):
python解释器本身就是一个程序 python.exe, 解释执行python脚本的。
python解释器运行起来之后本身就对应一个进程(运行着的程序)。
OS就自动的创建一个线程:
让它执行python解释器本身的代码。
当解释器执行我们python程序代码的时候。 我们的代码就在这个主线程中解释执行:
即我们写的代码去运行的时候,实在python解释器的主线程中去运行的。
Python代码中创建新线程
print('主线程执行代码')
# 从 threading 库中导入Thread类
from threading import Thread
from time import sleep
# 定义一个函数,作为新线程执行的入口函数
def threadFunc(arg1,arg2):
print('子线程 开始')
print(f'线程函数参数是:{arg1}, {arg2}')
sleep(5)
print('子线程 结束')
# 创建 Thread 类的实例对象
thread = Thread(
# target 参数 指定 新线程要执行的函数
# 注意,这里指定的函数对象只能写一个名字,不能后面加括号,
# 如果加括号就是直接在当前线程调用执行,而不是在新线程中执行了
target=threadFunc,
# 如果 新线程函数需要参数,在 args里面填入参数
# 注意参数是元组, 如果只有一个参数,后面要有逗号,像这样 args=('参数1',)
args=('参数1', '参数2')
)
# 执行start 方法,就会创建新线程,
# 并且新线程会去执行入口函数里面的代码。
# 这时候 这个进程 有两个线程了。
thread.start()
print('主线程结束')
没有join时,主线程先执行结束,然后大概5秒后子线程才结束,进程才结束。一个 Python 程序的整个进程,只有在 所有非守护线程(non-daemon thread)都结束后,才会真正退出
我们创建的 Thread 默认是 非守护线程 (daemon = False)
所以即使主线程已经执行完了 print(‘主线程结束’),进程仍然会等子线程执行完(即 print(‘子线程 结束’) 打印出来)之后才退出【参加daemon线程章节】。
join就是 等待参数对应的线程完成,才返回
thread = Thread(target=threadFunc,
args=('参数1', '参数2')
)
# target放的是函数对象,不能加括号,加括号就是执行这个函数了
共享数据的访问控制
10个线程,一开始取的初始值大概率就是0,所以即使线程2赋值为1了,但是线程3取到的不是1,而是0,再写会是1.
daemon线程
Python程序中当所有的 非daemon线程 结束了,整个程序才会结束
守护线程(daemon thread)
在 Python(以及很多语言)里,守护线程的特点是:
当进程里只剩下守护线程时,整个进程会直接退出,不会等待守护线程跑完。也就是说,守护线程是“陪跑线程”,不能阻止进程结束。
非守护线程 → 必须跑完,进程才能退出。
守护线程 → 主线程结束后不再管它,进程直接退出,子线程可能来不及执行完。
GIL = Global Interpreter Lock全局解释器锁
它主要影响的是 CPython 解释器里的多线程执行
多线程:
一个进程里多个线程,共用一个 GIL。
适合等网络、等文件、等 Redis。
多进程:
多个进程,每个进程一个 GIL。
适合 CPU 计算、模型推理、代码解析、编译、复杂任务。
即算用进程,等用线程



GIL 是什么?
简单说:
在同一个 Python 进程里,同一时刻通常只有一个线程能执行 Python 字节码
Python 多线程适合 I/O 密集型任务

CPU 密集型任务为什么多线程效果差?

多进程为什么可以绕开 GIL?
因为 每个进程都有自己独立的 Python 解释器和独立的 GIL。

更多推荐




所有评论(0)