一、并发与并行的区别
- 并发:一个时间段内,有几个程序在同一个CPU上运行,但是任意时刻只有一个程序在CPU上运行。
- 并行:并行是指任意时刻上,有多个程序同时运行在多个CPU上所有常说高并发,没有说高并行,因为CPU数量是有限的。
二、多进程与多线程的区别
- 对于耗 CPU 的操作,用多进程优于多线程,因为有 GIL 锁,不会常释放,耗 CPU 操作无法使用多线程。
- 多 IO 操作,常会释放 GIL,所以可以多使用多线程。
三、多进程编程
1. 使用 fork() 方法创建子进程(fork只能用于linux/unix中)。
import os
# fork只能用于linux/unix中
pid = os.fork()
print("bobby")
if pid == 0: # 子进程运行这段
print('子进程 {} ,父进程是: {}.' .format(os.getpid(), os.getppid()))
else: # 父进程运行这段
print('我是父进程:{}.'.format(pid))
"""
在 linux 下运行后,会打印:
bobby
我是父进程: 24474
bobby
子进程 24474, 父进程是:24473
"""
fork() 方法创建一个子进程,子进程会将父进程里的数据、代码原样拷贝到子进程当中,父进程依然会向下运行,父子进程都从 fork() 的地方继向下运行。
2. 使用 ProcessPoolExecutor 进行多进程编程。
from concurrent.futures import ProcessPoolExecutor
ProcessPoolExecutor 接口跟 ThreadPoolExecutor 的 api 几乎一模一样,具体使用方法可以参照上一篇博客:python线程池 ThreadPoolExecutor 使用详解
3. 使用 multiprocessing 模块进行多进程编程。
(1)multiprocessing.Process
import multiprocessing as mp
threads = []
for i in path:
threads.append(mp.Process(target=md5sum,args=(i,)))
#创建一个multiprocessing.process.Process对象
#执行
for m in threads:
m.start()
#回收
for m in threads:
m.join()
(2)使用线程池 multiprocessing.Pool()
def test():
pass
# 创建一个multiprocessing.pool.Pool的对象
p1 = mp.Pool(processes =5)
#向进程池里添加任务
result = pool.apply_async(test, args=(3,))
# 关闭进程池,阻止更多的任务提交到进程池Pool,待任务完成后,工作进程会退出
p1.close()
# 结束工作进程,不再处理未完成的任务
# p.terminate()
# 等待工作线程的退出,必须在close()或terminate()之后使用,因被终止的进程需要被父进程调用wait(join等价于wait),否则进程会成为僵尸进程。
p1.join()
print(result.get())
(a) Pool里有两种添加子进程的方法:
- apply_async 异步添加
- p1.apply(test) 阻塞式添加,逐步执行,相当于单进程
(b) 当Pool所有的进程任务完成后,会产生5个僵尸进程,如果主线程不结束,系统不会自动回收资源,需要调用join函数去回收。
(c) map() 方法:它融合了map函数和apply_async()函数的功能
(d) p.close():关闭进程池,阻止更多的任务提交到进程池Pool,待任务完成后,工作进程会退出
(e) p.terminate():结束工作进程,不再处理未完成的任务
(f) p.join():等待工作线程的退出,必须在close()或terminate()之后使用,因被终止的进程需要被父进程调用wait(join等价于wait),否则进程会成为僵尸进程。
参考文章: [Python]multiprocessing