前言&&
在其他语言中,CPU多核是支持多个线程同时执行。但在Python中,无论是单核还是多核,同时只能由一个线程在执行。其根源是GIL的存在。GIL的全称是Global Interpreter Lock(全局解释器锁),来源是Python设计之初的考虑,为了数据安全所做的决定。某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是“通行证”,并且在一个Python进程中,GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行。每次释放GIL锁,线程进行锁竞争、切换线程,会消耗资源,并且由于GIL锁存在,Python里一个进程永远只能同时执行一个线程(拿到GIL的线程才能执行),这就是为什么在多核CPU上,Python 的多线程效率并不高的根本原因。
如果我们在选择多线程还是多进程时,首先要看下你的程序是属于哪种类型的。一般分为两种:CPU密集型和I/O密集型。CPU 密集型(程序比较偏重于计算,需要经常使用CPU来运算。例如科学计算的程序,机器学习的程序等。),I/O 密集型(顾名思义就是程序需要频繁进行输入输出操作。爬虫程序就是典型的I/O密集型程序。),如果程序是属于CPU密集型,建议使用多进程。而多线程就更适合应用于I/O密集型程序。
import multiprocessing
import time, os
def func(msg):
print("msg:", msg)
time.sleep(3)
print("pid====>", os.getpid())
print("stop")
if __name__ == "__main__":
# 维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
pool = multiprocessing.Pool(processes = 10)
for i in range(5):
msg = f"start {i}"
# 非阻塞式,子进程不影响主进程的执行,会直接运行到 pool.join()
pool.apply_async(func, args=(msg, ))
# 阻塞式,先执行完子进程,再执行主进程
#pool.apply(func, (msg, ))
print("/./././././>>>>>><<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>")
# 调用join之前,先调用close函数,否则会出错。
pool.close()
# 执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束
pool.join()
print("all process down.")