这两天在跑一个文件处理程序的时候想着利用多核并行处理实现节省时间,然后例程里用了threading.Thread
来实现,结果依旧很慢,查看了一下cpu使用情况根本就是在单核上跑啊。查了一下才发现python中多线程存在PIL锁,什么意思呢,就是说这个锁使得同时只能有一个线程执行。。。。。这样的结果就是即使利用了多线程,多个线程仍旧是在单核上执行的,执行某一个线程的时候,余下的所有线程都吃瓜。
那怎么利用多核并行执行呢?python中提供了multiprocess模块可以实现这个需求。两种方式,第一种利用multiprocess.Process
,第二种利用进程池multiprocess.Pool
。
1.首先来看看多线程实现,代码如下:
from multiprocessing import cpu_count
import threading
def loop():
while True:
pass
if __name__ == '__main__':
threads = []
for i in range(cpu_count()):
t = threading.Thread(target=loop, args=[]) # 新建一个线程,target表示线程将要执行的函数,args表示函数的参数
threads.append(t)
t.start() # 启动线程
for t in threads:
t.join() # 线程等待,等子线程(t)执行结束完以后再结束主线程
while True:
pass
cpu_count()
是获取cpu核的个数的函数,这里让线程执行目标为死循环是为了简单粗暴地观察cpu使用情况。在我的四核cpu上执行结果如下:
可以看到基本上只消耗了一个cpu的资源,也就是说多线程的方式实际上并不能实现多核并行执行。下面来看看多进程的方式实现。
2. 多进程之multiprocess.Process
Process是python中用来创建进程的基础模块,后面的Pool也是基于Process来实现的。代码如下:
from multiprocessing import cpu_count
from multiprocessing import Process
def loop():
while True:
pass
if __name__ == '__main__':
threads = []
for i in range(cpu_count()):
t = Process(target=loop, args=[])
threads.append(t)
t.start()
for t in threads:
t.join()
while True:
pass
基本的代码步骤和前面多线程实现一样,运行上面代码再观察任务管理器结果如下:
可以看到此时cpu利用率达到了100%,我的破电脑四核cpu,执行上面的代码四个进程分别在四个核上并行执行。
3. 多进程之multiprocess.Pool
Pool:池子的意思,也就是进程池。multiprocess.Pool
首先建立一个固定大小的进程池,有需求来的话就让池中一个进程去执行任务(应该就是Process吧)。现在将上面的代码改写成进程池的实现:
from multiprocessing import cpu_count
from multiprocessing import Pool
def loop():
while True:
pass
if __name__ == '__main__':
p = Pool(cpu_count()) # 创建一个大小等于cpu核数的进程池
for i in range(cpu_count()): # 分配cpu核数个任务给每个进程并加入进程池
p.apply_async(loop, args=[]) # 这里用了异步非阻塞式
p.close() # 关闭进程池,不能再加入进程
p.join() # 主进程等进程池中所有子进程全结束再结束
while True:
pass
上面的代码执行结果如下:
- 同步阻塞式:
apply
- 异步非阻塞式:
apply_async
简单来说apply
方法是阻塞的,因此在一个子进程执行的时候,其他进程等待,等当前子进程执行结束之后再执行下一个。apply_async
方法是非阻塞的,根据系统调度来切换进程,不用等待进程结束。
如果把上面的程序中apply_async
改为apply
,结果会发现四个进程中只有一个会执行,占用cpu25%,其他都是0,并且由于死循环这个进程不会结束,其他进程根本不会执行。
总结
用到并行了大概了解了一下怎么实现,没有深入的学习,更详细地分析可以看以下文章。Pool的这个同步阻塞式方法也没有理解。。。。感觉只利用了单核cpu。。。
https://www.cnblogs.com/xiao987334176/p/9019884.html
python进程池apply与apply_async的区别