Skip to content

进程介绍

进程是计算机中资源分配的最小单元;一个进程中可以有多个线程,同一个进程中的线程共享资源;

进程与进程之间数据是相互隔离的。

Python中通过多进程可以利用CPU的多核优势,计算密集型操作适用于多进程。

启动进程的三种方法

根据不同的平台, multiprocessing 支持三种启动进程的方法,或者称之为模式,参考官网:https://docs.python.org/zh-cn/3.12/library/multiprocessing.html#contexts-and-start-methods

  • spawn

    父进程会启动一个新的 Python 解释器进程。子进程将只继承那些运行进程对象的 run() 方法所必须的资源。特别地,来自父进程的非必需文件描述符和句柄将不会被继承。 使用此方法启动进程相比使用 forkforkserver 要慢上许多。

    在 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的各种发行版本,不支持Windowsrun参数传必备资源不支持文件对象/线程锁等传参main代码块开始
spawn基于Unix的各种Linux发行版本,包括mac,支持Windowsrun参数传必备资源不支持文件对象/线程锁等传参main代码块开始

解释:

  • 操作系统支持,有些模式受限于操作系统的限制,所以你想要使用某个模式时,要考虑所在系统是否支持该系统。

  • 普通资源处理 ,主进程中开启子进程时,不同的模式对于主进程中的资源处理是不一样的,有的资源是默认拷贝给子进程的,有些需要传值声明给子进程用,有些是不允许给子进程使用的。

  • 特殊对象的处理,就是主进程中除了普通的资源,比如列表、字典这些,对于文件对象、锁等对象,不同的模式也是有不同的限制的。

  • 代码开始位置,因为有的模式会创建一个新的Python解释器,为了确保新的 Python 解释器可以安全地导入主模块,而不会导致意想不到的副作用(如启动新进程)。例如,使用 spawnforkserver 启动方式执行下面的模块,会引发 RuntimeError 异常而失败。

    官档:https://docs.python.org/zh-cn/3.12/library/multiprocessing.html#the-spawn-and-forkserver-start-methods

    python
    from multiprocessing import Process
    
    def foo():
        print('hello')
    
    p = Process(target=foo)
    p.start()

    应该通过下面的方法使用 if __name__ == '__main__': ,从而保护程序"入口点":

    python
    from 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系统来演示的。

python
"""
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']
"""
python
"""
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值一致,但以实际打印来看,不会相互影响,这是因为进程之间数据是隔离的。

python
"""
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动作
当子进程执行完,主进程也结束之后,文件中只有主进程写入的数据,而两个子进程中的写入并没有实际生效
这个现象要引起注意
"""
python
"""
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文件中的内容最后一行的由来。
"""
python
"""
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传参的形式给子进程传递资源,也就是让其拷贝资源。

python
"""
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']
"""
python
"""
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形式传递给子进程,特殊的文件对象之类的不支持传参拷贝资源。

python
"""
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']
"""
python
"""
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方法启动该进程。

python
"""
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()等待当前子进程的任务执行完毕,主进程才能继续往下执行。

python
"""
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解释器来说没有特别的意义。

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,设置为非守护进程,主进程等待子进程,子进程执行完毕后,主进程才结束。
python
"""
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方法中。

python
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的核心数我们也不用手动计算,也能代码获取。

python
"""
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)

进程间的数据共享和交换

进程是资源分配的最小单元,每个进程中都维护自己独立的数据,不共享。

python
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)  # []

如果想要让他们之间进行共享,则可以借助一些特殊的东西来实现。

另外,进程之间的数据共享在具体实现方面也是有细微区别的。

进程锁

进程池