多进程是指在同一时间内,同时执行多个程序或多个部分的程序。每个进程都拥有自己的地址空间、内存、文件描述符和其他系统资源。多进程的好处在于可以使程序并行执行,从而提高程序的运行效率。
Python中的multiprocessing模块提供了一种创建和管理进程的方式,使得可以利用多个CPU来加速程序运行。
multiprocessing模块提供了一个Process类,可以用来创建和管理进程。下面是一个简单的示例:
import multiprocessing
def worker():
"""该函数将在子进程中执行"""
print('Worker')
if __name__ == '__main__':
# 创建子进程
p = multiprocessing.Process(target=worker)
# 启动子进程
p.start()
# 等待子进程结束
p.join()
在上面的代码中,worker函数将在子进程中执行。首先,创建了一个Process对象,指定target参数为worker函数。然后,通过调用start方法启动子进程,最后调用join方法等待子进程结束。
这地方用到的是args和kwargs,其中args是使用元素组的方式给指定任务传参,kwargs是使用字典方式给指定任务传参。
进程对象 = multiprocessing.Process(target=*,args=(*,))
此处注意,若只有一个元素,那个逗号也是不可以省略的。
进程对象 = multiprocessing.Process(target=*,kwargs={"变量名": 变量值})
例子
import time
import multiprocessing
def eat(num,name):
for i in range(num):
print(name+"吃一口……")
time.sleep(1)
def drink(num,name):
for i in range(num):
print(name+"喝一口……")
time.sleep(1)
if __name__ == '__main__':
# target:指定执行的函数名
# args:使用元组方式给指定任务传参
# kwargs:使用字典方式给指定任务传参
eat_process = multiprocessing.Process(target=eat,args=(3,"giao"))
drink_process = multiprocessing.Process(target=drink,kwargs={"num": 4,"name":"giao"})
eat_process.start()
drink_process.start()
获取进程的编号
获取当前进程的编号
os.getpid()
os.getppid()
当参数daemon是False时,主进程结束了子进程还是会继续执行;否则,子进程和主进程一起结束,默认False。
当主进程结束时,要让子进程也不再继续执行,直接结束,我们可以通过进程对象的参数daemon来进行控制。
只需要在创建进程之后,加入这样一句代码
进程名称.daemon = True
这样子进程就会守护主进程,主进程结束,子进程也会自动销毁。
例子
import multiprocessing
import time
def eat():
for i in range(10):
print("我吃我吃……")
time.sleep(0.5)
if __name__ == '__main__':
eat_process = multiprocessing.Process(target=eat)
# 设置进程守护
eat_process.daemon = True
eat_process.start()
time.sleep(1)
print("我吃饱了……")
创建进程的方式
方式1:使用Process直接创建
# 创建子进程
p = multiprocessing.Process(target=worker)
如果需要创建大量的进程,那么使用Process类可能会导致系统资源的浪费。此时,可以使用Pool类来创建进程池。下面是一个简单的示例:
import multiprocessing
import os
import time
def worker(num):
"""该函数将在子进程中执行"""
time.sleep(4)
print('Worker %d , 进程id为 %d' %(num,os.getpid()))
if __name__ == '__main__':
# 创建进程池
pool = multiprocessing.Pool(4) # 设置进程池中进程最大数量是4
# 启动进程池中的进程
pool.map(worker, range(10)) # 需要开启10个进程
# 关闭进程池
pool.close()
# 等待进程池中的进程结束
pool.join()
在上面的代码中,Pool类的构造函数中指定了进程池的大小为4,然后通过调用map方法来启动进程池中的进程。map方法会将worker函数和range(10)序列中的每个元素一一对应,然后将它们作为参数传递给进程池中的进程。此外,需要的10个进程会从进程池中拿3次。
Worker 0 , 进程id为 14948
Worker 1 , 进程id为 28360
Worker 2 , 进程id为 30592
Worker 3 , 进程id为 22260
---上4组并行
Worker 4 , 进程id为 14948
Worker 5 , 进程id为 28360
Worker 6 , 进程id为 30592
Worker 7 , 进程id为 22260
---上4组并行
Worker 8 , 进程id为 14948
Worker 9 , 进程id为 28360
---上2组并行
Process finished with exit code 0
进程池的进程最大数量最多不超过计算机的cpu核心数量,以下函数cpu_count()可以获取到当前计算机的cpu核心数量
import multiprocessing
cpus = multiprocessing.cpu_count()
pool = multiprocessing.Pool(cpus)
进程执行方法需要多个参数:
https://blog.csdn.net/u013421629/article/details/100284962
每个进程需要执行的方法有多个参数需要如何处理?比如上面的worker方法中有两个参数,那么pool.map调用的时候会报错,例子如下:
data_list=[(1,1),(2,2),(3,3)]
res = pool.map(worker,data_list)
def worker(num,num2):
time.sleep(4)
print('Worker %d , 进程id为 %d' %(num,os.getpid()))
会报出:参数个数不匹配的错误。
解决方法1:多个参数合并成一个参数(list),需要重新定义一个方法worker,该方法只有一个形式参数,其内部再调用多参数的方法,如下:
def worker2(s:list):
worker(s[0],s[1])
data_list=[(1,1),(2,2),(3,3)]
res = pool.map(worker2,data_list)
此外,你可能会有使用lambda表达式的思路,生成一个匿名函数worker2,然后调用worker,就像这样
worker2 = lambda x:worker(x[0],x[1])
res = pool.map(worker2,data_list)
然后就会发现,不行,报错,如下
File "/usr/lib/python3.10/multiprocessing/connection.py", line 206, in send
self._send_bytes(_ForkingPickler.dumps(obj))
File "/usr/lib/python3.10/multiprocessing/reduction.py", line 51, in dumps
cls(buf, protocol).dump(obj)
AttributeError: Can't pickle local object 'worker..'
其实,还有另外一种方法,让我们直接就可以把多参的函数穿传入进来。如下
解决方法2:使用pathos.multiprocessing,可以传入多个参数的方法f,代码如下,不多此时,map的第二个参数就是f的第一个参数的list,map的第三个参数就是f的第二个参数的list。
>>> from pathos.multiprocessing import ProcessingPool as Pool
>>>
>>> def add_and_subtract(x,y):
... return x+y, x-y
>>> res = Pool().map(add_and_subtract, range(0,20,2), range(-5,5,1))
>>> res
[(-5, 5), (-2, 6), (1, 7), (4, 8), (7, 9), (10, 10), (13, 11), (16, 12), (19, 13), (22, 14)]
比如,Pool().map(add,[0,1,2],[3,4,5]),代表add(0,3),add(1,4),add(2,5)这三个函数并行
参考:
http://stack.itcast.cn/news/20230404/10534657760.shtml
https://www.rstk.cn/news/45013.html?action=onClick