进程介绍
进程是计算机中资源分配的最小单元;一个进程中可以有多个线程,同一个进程中的线程共享资源;
进程与进程之间数据是相互隔离的。
Python中通过多进程可以利用CPU的多核优势,计算密集型操作适用于多进程。
启动进程的三种方法
根据不同的平台, multiprocessing
支持三种启动进程的方法,或者称之为模式,参考官网:https://docs.python.org/zh-cn/3.12/library/multiprocessing.html#contexts-and-start-methods
spawn
父进程会启动一个新的 Python 解释器进程。子进程将只继承那些运行进程对象的
run()
方法所必须的资源。特别地,来自父进程的非必需文件描述符和句柄将不会被继承。 使用此方法启动进程相比使用 fork 或 forkserver 要慢上许多。在 POSIX 和 Windows 平台上可用。 默认在Windows 和 macOS 上是默认方式。
fork
父进程使用
os.fork()
来产生 Python 解释器分叉。子进程在开始时实际上与父进程相同。父进程的所有资源都由子进程继承。请注意,安全分叉多线程进程是棘手的。在 POSIX 系统上可用。 目前在除 macOS 之外的 POSIX 上为默认值,即你可以理解为在我们常用的Linux系统上是默认方式
注意,在Python 3.14 上默认的启动方法将不再为 fork。 需要 fork 的代码应当显式地通过
get_context()
或set_start_method()
来指定。在 3.12 版本发生变更: 如果 Python 能够检测到你的进程有多个线程,那么在该启动方法内部调用
os.fork()
函数将引发DeprecationWarning
。 请使用其他启动方法。 进一步的解释参见os.fork()
文档。forkserver
当程序启动并选择 forkserver 启动方法时,将产生一个服务器进程。从那时起,每当需要一个新进程时,父进程就会连接到该服务器并请求它分叉一个新进程。 分叉服务器进程是单线程的,除非因系统库或预加载导入的附带影响改变了这一点,因此使用
os.fork()
通常是安全的。 没有不必要的资源被继承。在支持通过 Unix 管道传递文件描述符的 POSIX 平台上可用,例如 Linux。
方式 | 操作系统支持 | 普通资源处理 | 特殊对象的处理 | 代码开始位置 | 执行速度 |
---|---|---|---|---|---|
fork | 基于Unix的各种Linux发行版本,包括mac,不支持Windows | "拷贝"几乎所有普通资源 | 支持文件对象/线程锁等传参 | 任意位置可以都可以创建子进程 | 快 |
forkserver | 部分Unix的各种发行版本,不支持Windows | run参数传必备资源 | 不支持文件对象/线程锁等传参 | main代码块开始 | 快 |
spawn | 基于Unix的各种Linux发行版本,包括mac,支持Windows | run参数传必备资源 | 不支持文件对象/线程锁等传参 | main代码块开始 | 慢 |
解释:
操作系统支持,有些模式受限于操作系统的限制,所以你想要使用某个模式时,要考虑所在系统是否支持该系统。
普通资源处理 ,主进程中开启子进程时,不同的模式对于主进程中的资源处理是不一样的,有的资源是默认拷贝给子进程的,有些需要传值声明给子进程用,有些是不允许给子进程使用的。
特殊对象的处理,就是主进程中除了普通的资源,比如列表、字典这些,对于文件对象、锁等对象,不同的模式也是有不同的限制的。
代码开始位置,因为有的模式会创建一个新的Python解释器,为了确保新的 Python 解释器可以安全地导入主模块,而不会导致意想不到的副作用(如启动新进程)。例如,使用 spawn 或 forkserver 启动方式执行下面的模块,会引发
RuntimeError
异常而失败。pythonfrom multiprocessing import Process def foo(): print('hello') p = Process(target=foo) p.start()
应该通过下面的方法使用
if __name__ == '__main__':
,从而保护程序"入口点":pythonfrom multiprocessing import Process, freeze_support, set_start_method def foo(): print('hello') if __name__ == '__main__': freeze_support() set_start_method('spawn') p = Process(target=foo) p.start()
当然了,为了养成好的编程习惯,我们的启动代码都应该放到main的代码块中。
通常我们在使用多进程时,无需关注这些模式,让其根据系统平台自行决定使用默认模式即可。
fork
fork模式在创建子进程时,默认会"拷贝"几乎所有的父进程的资源,包括文件对象、线程锁等。
注意
Windows系统不支持fork模式。
所以fork模式相关的代码示例,我都是以ubuntu20.04系统来演示的。
"""
ubuntu20.04
对于普通的资源,fork模式会拷贝一份,
是否显示以传参的形式传递资源,都不影响子进程中使用
对于特殊的资源,比如文件对象,也是会拷贝一份的
"""
import time
import multiprocessing
def task1():
print(multiprocessing.current_process().name, id(user), user, f)
user.append('likai')
time.sleep(0.5)
print(multiprocessing.current_process().name, id(user), user, f)
def task2(user, f):
print(multiprocessing.current_process().name, id(user), user, f)
user.append('sunkai')
time.sleep(0.5)
print(multiprocessing.current_process().name, id(user), user, f)
if __name__ == '__main__':
# 设置开启子进程的模式
multiprocessing.set_start_method("fork") # fork、spawn、forkserver
user = []
user.append("zhangkai")
f = open('a.txt', 'w', encoding='utf8')
# 当开启子进程时,会将父进程的name列表也拷贝一份,这俩name在后续的操作中,不会相互影响
# 另外,还有需要你注意的是,由于fork模式默认会拷贝父进程的资源,所以在创建子进程时,
# 我们并没有传递资源,但子进程中也可以直接使用
# 当然就算传递资源,也是可以的
p1 = multiprocessing.Process(target=task1, name='p1')
p1.start()
p2 = multiprocessing.Process(target=task2, args=(user, f), name='p2')
p2.start()
time.sleep(1)
print('主进程', id(user), user) # 主进程 140146878793600 ['zhangkai']
time.sleep(2)
print('主进程', id(user), user) # 主进程 140146878793600 ['zhangkai']
"""
p1 140547565684608 ['zhangkai'] <_io.TextIOWrapper name='a.txt' mode='w' encoding='utf8'>
p2 140547565684608 ['zhangkai'] <_io.TextIOWrapper name='a.txt' mode='w' encoding='utf8'>
p2 140547565684608 ['zhangkai', 'sunkai'] <_io.TextIOWrapper name='a.txt' mode='w' encoding='utf8'>
p1 140547565684608 ['zhangkai', 'likai'] <_io.TextIOWrapper name='a.txt' mode='w' encoding='utf8'>
主进程 140547565684608 ['zhangkai']
主进程 140547565684608 ['zhangkai']
"""
"""
Windows系统不支持fork模式,所以你硬要使用fork模式,会报错
ValueError: cannot find context for 'fork'
"""
import time
import multiprocessing
def task():
print("子进程", id(user), user) # 子进程 140492812814144 ['zhangkai']
user.append('likai')
time.sleep(1)
print("子进程", id(user), user) # 子进程 140492812814144 ['zhangkai', 'likai']
if __name__ == '__main__':
# 设置开启子进程的模式
multiprocessing.set_start_method("fork") # fork、spawn、forkserver
user = []
user.append("zhangkai")
p1 = multiprocessing.Process(target=task)
p1.start()
print('主进程', id(user), user) # 主进程 140492812814144 ['zhangkai']
time.sleep(2)
print('主进程', id(user), user) # 主进程 140492812814144 ['zhangkai']
上面示例中,虽然子进程拷贝走的user id值和父进程的user id值一致,但以实际打印来看,不会相互影响,这是因为进程之间数据是隔离的。
"""
ubuntu20.04
对于特殊对象,如文件对象,我们来进一步看一下一些现象
"""
import multiprocessing
def task1():
f.write('likai\n')
# f.flush()
def task2():
f.write('sunkai\n')
# f.flush()
if __name__ == '__main__':
# 设置开启子进程的模式
multiprocessing.set_start_method("fork") # fork、spawn、forkserver
user = []
user.append("zhangkai")
f = open('a.txt', 'a+', encoding='utf8')
f.write('zhangkai\n')
# f.flush()
p1 = multiprocessing.Process(target=task1, name='p1')
p1.start()
p2 = multiprocessing.Process(target=task2, name='p2')
p2.start()
"""
a.txt文件中的内容:
zhangkai
"""
"""
在fork模式下
当所有的f.flush()都注释之后,那么主进程中创建了文件对象,并且写入了zhangkai,但此时并没有写入到本地
而是先写入到内存中了,紧接着就创建了两个子进程,而fork模式子进程会拷贝父进程的资源,也包括文件对象
然后子进程中也各自进行了f.write动作,但都没有flash动作
当子进程执行完,主进程也结束之后,文件中只有主进程写入的数据,而两个子进程中的写入并没有实际生效
这个现象要引起注意
"""
"""
ubuntu20.04
在这个示例中,我们放开task1中的f.flush(),观察执行结果
"""
import multiprocessing
def task1():
f.write('likai\n')
f.flush()
def task2():
f.write('sunkai\n')
# f.flush()
if __name__ == '__main__':
# 设置开启子进程的模式
multiprocessing.set_start_method("fork") # fork、spawn、forkserver
user = []
user.append("zhangkai")
f = open('a.txt', 'a+', encoding='utf8')
f.write('zhangkai\n')
# f.flush()
p1 = multiprocessing.Process(target=task1, name='p1')
p1.start()
p2 = multiprocessing.Process(target=task2, name='p2')
p2.start()
"""
a.txt文件中的内容:
zhangkai
likai
zhangkai
"""
"""
这个示例的执行结果,a.txt文件中的内容的前两行都是子进程的写入动作,因为fork模式下,p1子进程拷贝了父进程的文件
对象,这个对象也包含着主进程往文件对象中写入的zhangkai,所以子进程在写入likai之后,f.flush()会把这两行
内容写入到本地然后子进程结束。
p2子进程由于没有f.flush()动作,那p2的执行结果就是相当于啥也没做,然后p2结束。
主进程往下继续执行,没什别的代码了,准备结束,在结束之前,把主进程中的f.write('zhangkai\n')
这个写入到内存中的数据,在真正的写入到文件中,也就是a.txt文件中的内容最后一行的由来。
"""
"""
ubuntu20.04
在这个示例中,我们放开主进程中和task1中的f.flush(),观察执行结果
"""
import multiprocessing
def task1():
f.write('likai\n')
f.flush()
def task2():
f.write('sunkai\n')
# f.flush()
if __name__ == '__main__':
# 设置开启子进程的模式
multiprocessing.set_start_method("fork") # fork、spawn、forkserver
user = []
user.append("zhangkai")
f = open('a.txt', 'a+', encoding='utf8')
f.write('zhangkai\n')
f.flush()
p1 = multiprocessing.Process(target=task1, name='p1')
p1.start()
p2 = multiprocessing.Process(target=task2, name='p2')
p2.start()
"""
zhangkai
likai
"""
"""
这个示例的执行结果,a.txt文件中的内容,第一行的zhangkai是由主进程先写入到本地之后,此时文件对象中没有其他的数据,
然后被p1子进程拷贝走,p1内部写入并刷写到硬盘,p1执行结束,这是第二行内容的由来。
p2子进程由于没有f.flush()动作,那p2的执行结果就是相当于啥也没做,然后p2结束。
主进程继续往下走,没啥代码了,进程结束了。
"""
spawn
spawn模式默认是不会"拷贝"父进程的资源的,如果有需要父进程给子进程传递什么资源,比如传递给子进程一个列表,那就要通过手动以args传参的形式给子进程传递资源,也就是让其拷贝资源。
"""
ubuntu20.04 & windows运行结果一致
spawn模式下,创建的子进程默认不会拷贝父进程的资源,所以p1子进程中直接使用了user列表和文件对象f
因此会导致报错 NameError: name 'user' is not defined
子进程需要拷贝什么资源,都需要args传参的形式给子进程传递,如p2,并且数据仍是隔离的。
"""
import time
import multiprocessing
# def task1():
# print(multiprocessing.current_process().name, id(user), user, f)
# user.append('likai')
# time.sleep(0.5)
# print(multiprocessing.current_process().name, id(user), user, f)
def task2(user):
print(multiprocessing.current_process().name, id(user), user)
user.append('sunkai')
time.sleep(0.5)
print(multiprocessing.current_process().name, id(user), user)
if __name__ == '__main__':
# 设置开启子进程的模式
multiprocessing.set_start_method("spawn") # fork、spawn、forkserver
user = []
user.append("zhangkai")
# p1 = multiprocessing.Process(target=task1, name='p1')
# p1.start()
p2 = multiprocessing.Process(target=task2, args=(user,), name='p2')
p2.start()
time.sleep(1)
print('主进程', id(user), user)
time.sleep(2)
print('主进程', id(user), user)
"""
p2 139633036118976 ['zhangkai']
p2 139633036118976 ['zhangkai', 'sunkai']
主进程 140511638669184 ['zhangkai']
主进程 140511638669184 ['zhangkai']
"""
"""
ubuntu20.04 & windows运行结果一致
spawn模式不支持文件对象/线程锁对象的拷贝,也不支持传参的形式拷贝资源,所以如下
p2中,就算传参的形式传递文件对象,子进程中也用不了,就会导致报错
所以,不要在spawn模式下去搞什么拷贝资源的动作,子进程中需要啥,自己搞啥
"""
import time
import multiprocessing
# def task1():
# print(multiprocessing.current_process().name, id(user), user, f)
# user.append('likai')
# time.sleep(0.5)
# print(multiprocessing.current_process().name, id(user), user, f)
# # f.write('likai\n')
# # f.flush()
def task2(user, f):
print(multiprocessing.current_process().name, id(user), user, f)
user.append('sunkai')
time.sleep(0.5)
print(multiprocessing.current_process().name, id(user), user, f)
# f.write('sunkai\n')
if __name__ == '__main__':
# 设置开启子进程的模式
multiprocessing.set_start_method("spawn") # fork、spawn、forkserver
user = []
user.append("zhangkai")
f = open('a.txt', 'w', encoding='utf8')
# f.write('zhangkai\n')
# f.flush()
# p1 = multiprocessing.Process(target=task1, name='p1')
# p1.start()
p2 = multiprocessing.Process(target=task2, args=(user, f), name='p2')
p2.start()
time.sleep(1)
print('主进程', id(user), user)
time.sleep(2)
print('主进程', id(user), user)
"""
TypeError: cannot pickle '_io.TextIOWrapper' object
"""
forkserver
forkserver模式跟spawn模式类似,也是普通资源以args形式传递给子进程,特殊的文件对象之类的不支持传参拷贝资源。
"""
ubuntu20.04运行正常
forkserver模式下,创建的子进程默认不会拷贝父进程的资源,所以p1子进程中直接使用了user列表和文件对象f
因此会导致报错 NameError: name 'user' is not defined
子进程需要拷贝什么资源,都需要args传参的形式给子进程传递,如p2,并且数据仍是隔离的。
注意,Windows不支持forkserver模式,你在Windows系统运行下面代码会报错
ValueError: cannot find context for 'forkserver'
"""
import time
import multiprocessing
# def task1():
# print(multiprocessing.current_process().name, id(user), user, f)
# user.append('likai')
# time.sleep(0.5)
# print(multiprocessing.current_process().name, id(user), user, f)
def task2(user):
print(multiprocessing.current_process().name, id(user), user)
user.append('sunkai')
time.sleep(0.5)
print(multiprocessing.current_process().name, id(user), user)
if __name__ == '__main__':
# 设置开启子进程的模式
multiprocessing.set_start_method("forkserver") # fork、spawn、forkserver
user = []
user.append("zhangkai")
# p1 = multiprocessing.Process(target=task1, name='p1')
# p1.start()
p2 = multiprocessing.Process(target=task2, args=(user,), name='p2')
p2.start()
time.sleep(1)
print('主进程', id(user), user)
time.sleep(2)
print('主进程', id(user), user)
"""
p2 139633036118976 ['zhangkai']
p2 139633036118976 ['zhangkai', 'sunkai']
主进程 140511638669184 ['zhangkai']
主进程 140511638669184 ['zhangkai']
"""
"""
ubuntu20.04运行代码正常
forkserver模式不支持文件对象/线程锁对象的拷贝,也不支持传参的形式拷贝资源,所以如下
p2中,就算传参的形式传递文件对象,子进程中也用不了,就会导致报错
所以,不要在forkserver模式下去搞什么拷贝资源的动作,子进程中需要啥,自己搞啥
注意,Windows不支持forkserver模式,你在Windows系统运行下面代码会报错
ValueError: cannot find context for 'forkserver'
"""
import time
import multiprocessing
# def task1():
# print(multiprocessing.current_process().name, id(user), user, f)
# user.append('likai')
# time.sleep(0.5)
# print(multiprocessing.current_process().name, id(user), user, f)
# # f.write('likai\n')
# # f.flush()
def task2(user, f):
print(multiprocessing.current_process().name, id(user), user, f)
user.append('sunkai')
time.sleep(0.5)
print(multiprocessing.current_process().name, id(user), user, f)
# f.write('sunkai\n')
if __name__ == '__main__':
# 设置开启子进程的模式
multiprocessing.set_start_method("forkserver") # fork、spawn、forkserver
user = []
user.append("zhangkai")
f = open('a.txt', 'w', encoding='utf8')
# f.write('zhangkai\n')
# f.flush()
# p1 = multiprocessing.Process(target=task1, name='p1')
# p1.start()
p2 = multiprocessing.Process(target=task2, args=(user, f), name='p2')
p2.start()
time.sleep(1)
print('主进程', id(user), user)
time.sleep(2)
print('主进程', id(user), user)
"""
TypeError: cannot pickle '_io.TextIOWrapper' object
"""
多进程的常用姿势
Process类用来实例化一个进程对象,Process
类拥有和 threading.Thread
等价的大部分方法,也就是跟多线程的套路差不多,都有start、join、run、daemon这些方法,所以接下来我们快速了解下。
p.start()
创建一个进程对象,通过start方法启动该进程。
"""
ubuntu20.04 & windows运行结果一致
"""
import multiprocessing
def task1():
print(multiprocessing.current_process().name)
def task2(user):
print(multiprocessing.current_process().name, user)
if __name__ == '__main__':
# 设置开启子进程的模式
multiprocessing.set_start_method("spawn") # fork、spawn、forkserver
user = []
user.append("zhangkai")
p1 = multiprocessing.Process(target=task1)
p1.start()
p2 = multiprocessing.Process(target=task2, args=(user,))
p2.start()
print('主进程')
"""
主进程
Process-1
Process-2 ['zhangkai']
"""
p.join()
p.join()
等待当前子进程的任务执行完毕,主进程才能继续往下执行。
"""
ubuntu20.04 & windows运行结果一致
"""
import multiprocessing
def task1():
print(multiprocessing.current_process().name)
def task2(user):
print(multiprocessing.current_process().name, user)
if __name__ == '__main__':
# 设置开启子进程的模式
multiprocessing.set_start_method("spawn") # fork、spawn、forkserver
user = []
user.append("zhangkai")
# --------------------------- 常见写法1 ---------------------------
# p1 = multiprocessing.Process(target=task1)
# p1.start()
# p1.join() # 阻塞主进程,等待子进程结束
#
# p2 = multiprocessing.Process(target=task2, args=(user,))
# p2.start()
# p2.join() # 阻塞主进程,等待子进程结束
# print('主进程')
# --------------------------- 常见写法2 ---------------------------
# p1 = multiprocessing.Process(target=task1)
# p2 = multiprocessing.Process(target=task2, args=(user,))
# # 启动多个子进程
# p1.start()
# p2.start()
#
# p1.join() # 阻塞主进程,等待子进程结束
# p2.join() # 阻塞主进程,等待子进程结束
# print('主进程')
# --------------------------- 常见写法3 ---------------------------
# p_start = []
# p_join = []
# for i in range(5):
# p = multiprocessing.Process(target=task1)
# p_start.append(p)
# p_join.append(p)
#
# # 统一启动多个子进程
# for p in p_start:
# p.start()
# # 统一join
# for p in p_join:
# p.join()
# print('主进程')
进程名字和进程PID
稍微对操作系统有了解的同学一定对进程名和进程pid非常熟悉,比如在Linux中,我们通常根据进程名称和进程的pid来确认进程是否存活,或者杀死这个进程。
在多进程中,我们可以为子进程起一个名字字符串类型的名字,甚至可以为多个进程赋予相同的名字,所以它只是用来我们在程序中识别它,即对我们有用,但对于Python解释器来说没有特别的意义。
"""
ubuntu20.04 & windows运行结果一致
# 获取进程名
multiprocessing.current_process().name
# 获取进程pid
multiprocessing.current_process().pid
"""
import time
import multiprocessing
def task1():
print("子进程", multiprocessing.current_process().name, multiprocessing.current_process().pid)
count = 0
while count <= 1000000:
time.sleep(0.001)
count += 1
if __name__ == '__main__':
# 设置开启子进程的模式
multiprocessing.set_start_method("spawn")
# p = multiprocessing.Process(target=task1, name='p1') # 可通过name指定进程名称
p = multiprocessing.Process(target=task1)
p.start()
print('主进程', multiprocessing.current_process().name, multiprocessing.current_process().pid)
time.sleep(100)
"""
主进程 MainProcess 37350
子进程 Process-1 37354
"""
"""
ubuntu20.04中执行上面示例之后,在程序结束之前,可以打开终端过滤出来
(celerypy) moluo@ubuntu:~/Desktop/demo$ ps -ef|grep python
moluo 37350 5899 0 10:59 ? 00:00:00 /home/moluo/anaconda3/envs/celerypy/bin/python /home/moluo/Desktop/demo/test.py
moluo 37353 37350 0 10:59 ? 00:00:00 /home/moluo/anaconda3/envs/celerypy/bin/python -c from multiprocessing.resource_tracker import main;main(4)
moluo 37354 37350 1 10:59 ? 00:00:00 /home/moluo/anaconda3/envs/celerypy/bin/python -c from multiprocessing.spawn import spawn_main; spawn_main(tracker_fd=5, pipe_handle=7) --multiprocessing-fork
moluo 37369 19280 0 11:00 pts/4 00:00:00 grep --color=auto python
"""
p.daemon
p.daemon = 布尔值
,守护进程(必须放在start之前)
p.daemon =True
,设置为守护进程,主进程执行完毕后,子进程也自动关闭。p.daemon =False
,设置为非守护进程,主进程等待子进程,子进程执行完毕后,主进程才结束。
"""
ubuntu20.04 & windows运行结果一致
"""
import time
import multiprocessing
def task1():
print("子进程", multiprocessing.current_process().name, multiprocessing.current_process().pid)
if __name__ == '__main__':
# 设置开启子进程的模式
multiprocessing.set_start_method("spawn") # fork、spawn、forkserver
# 可以传参设置守护进程
p = multiprocessing.Process(target=task1, daemon=True)
# 也可以通过赋值设置,注意必须在start之前设置
# p.daemon = True # 同时设置的话,这个会覆盖掉上面那个
p.start()
print('主进程', multiprocessing.current_process().name, multiprocessing.current_process().pid)
time.sleep(1)
自定义进程类
跟自定义线程类一样,直接将子进程需要做的事写到run方法中。
import multiprocessing
class MyProcess(multiprocessing.Process):
def run(self):
print('执行此进程', self._args)
if __name__ == '__main__':
multiprocessing.set_start_method("spawn")
p = MyProcess(args=('xxx',))
p.start()
print("继续执行...")
多进程开多少合适?有上限吗?
开子进程要比开子线程有更多的资源和时间开销,所以,开多进程也不是无上限的,那么开多少合适呢?根据经验来看,多进程的上线应该不超过CPU核心数(指的是逻辑核心数),或者不要超过2倍CPU核心数。
当然了,具体你的电脑适合多少,要根据具体的业务,慢慢往上调整,然后观察耗时,找到一个合适的区间,因为有的时候,开的多了,反而整个程序执行时间会更长了。
实在懒得测,就开到跟CPU核心数一样就行了,当然了,CPU的核心数我们也不用手动计算,也能代码获取。
"""
ubuntu20.04 & windows运行结果一致
"""
import os
import time
import multiprocessing
def task1():
print("子进程", multiprocessing.current_process().name, multiprocessing.current_process().pid)
if __name__ == '__main__':
# 设置开启子进程的模式
multiprocessing.set_start_method("spawn") # fork、spawn、forkserver
# 两种方式获取CPU的核心数
# print(os.cpu_count())
# print(multiprocessing.cpu_count())
for i in range(os.cpu_count()):
p = multiprocessing.Process(target=task1)
p.start()
print('主进程', multiprocessing.current_process().name, multiprocessing.current_process().pid)
time.sleep(1)
进程间的数据共享和交换
进程是资源分配的最小单元,每个进程中都维护自己独立的数据,不共享。
import multiprocessing
def task(data):
data.append(666)
print("子进程:", data) # [666]
if __name__ == '__main__':
data_list = []
p = multiprocessing.Process(target=task, args=(data_list,))
p.start()
p.join()
print("主进程:", data_list) # []
如果想要让他们之间进行共享,则可以借助一些特殊的东西来实现。
另外,进程之间的数据共享在具体实现方面也是有细微区别的。