Python多进程
本文最后更新于 2026年8月22日
未完待续
进程是操作系统进行资源分配的基本单位,每个进程拥有一块独立的内存空间,可以通过python os模块的方法来获取当前运行python程序的所属进程号和父进程号,在任务管理器中,通过进程号能查找到对应进程
import os
print(os.getpid())
print(os.getppid())27516
13228在Pycharm IDE中启动python解释器时,父进程往往就是Pycharm IDE


1.创建进程
python使用multiprocessing.Process类来管理进程,创建进程时就要通过target制定好进程将要执行的任务,创建后,调用start()方法,向操作系统申请进程,将该进程交给操作系统进行调度,子进程才会真的启动。可以使用multiprocessing.current_process()方法获取当前进程
创建进程的Process(target=study)必须出现在 if __name__ == '__main__':内,因为当新进程创建时,python底层会启动一个新的解释器,再次运行study函数所在py文件,只获得study函数的定义交给子进程,如果没有 if __name__ == '__main__':判断,Process(target=study)也会被新的解释器进程执行到,最终出现死循环创建进程
当子进程的解释器运行py文件时,
__name__也是有值的,它的值是:__mp_main__
执行时,主/子进程执行是异步的,子进程执行不影响主进程
子进程之间也不一定是先start()的先执行,一切以操作系统调度为准
import os
import time
from multiprocessing import Process, current_process
print('hello world ', __name__)
def study():
for i in range(100):
print('%s %s 父进程 %s 进程 %s Study' % (current_process(), i, os.getppid(), os.getpid()) , end='\n')
time.sleep(1)
def speak():
for i in range(100):
print('%s %s 父进程 %s 进程 %s speak' % (current_process(), i, os.getppid(), os.getpid()) , end='\n')
time.sleep(1)
if __name__ == '__main__':
print('主进程开始执行')
print('主进程 ', os.getpid())
p1 = Process(target=study)
p2 = Process(target=speak)
p1.start()
p2.start()
print('主进程结束执行')
hello world __main__
主进程开始执行
主进程 12080
主进程结束执行
hello world __mp_main__
<Process name='Process-3' parent=12080 started> 0 父进程 12080 进程 45936 Study
hello world __mp_main__
<Process name='Process-4' parent=12080 started> 0 父进程 12080 进程 44440 speak
<Process name='Process-3' parent=12080 started> 1 父进程 12080 进程 45936 Study
<Process name='Process-4' parent=12080 started> 1 父进程 12080 进程 44440 speak
<Process name='Process-3' parent=12080 started> 2 父进程 12080 进程 45936 Study
<Process name='Process-4' parent=12080 started> 2 父进程 12080 进程 44440 speak
<Process name='Process-3' parent=12080 started> 3 父进程 12080 进程 45936 Study
<Process name='Process-4' parent=12080 started> 3 父进程 12080 进程 44440 speak
<Process name='Process-3' parent=12080 started> 4 父进程 12080 进程 45936 Study
<Process name='Process-4' parent=12080 started> 4 父进程 12080 进程 44440 speak
<Process name='Process-3' parent=12080 started> 5 父进程 12080 进程 45936 Study
<Process name='Process-4' parent=12080 started> 5 父进程 12080 进程 44440 speak
.............Process类有以下参数,有的是继承来的:
group默认为Nonetarget子进程要运行的可执行对象,默认为Nonename进程名,默认None,系统自动分配名字args为目标target传递的位置可变(元组)参数kwargs为目标target传递的关键字可变(字典)参数daemon布尔值,是否为守护进程,默认为None意思是从父进程继承
2.进程锁
python多进程打印会出现抢占现象,例如本程序打印时,有的打印会出现一行超过4个字符,不到4个字符或数字字母字符混在一行的情况,在python中,打印语句执行时,会先打印内容,再打印end=,如果一个进程打印完内容还没有打印end=,控制台就被另一进程抢走打印其他进程的内容,就会出现这个现象。
from multiprocessing import Process, current_process
def study():
for i in range(800):
print('a', end='')
print('b', end='')
print('c', end='')
print('d', end='\n')
def speak():
for i in range(800):
print('1', end='')
print('2', end='')
print('3', end='')
print('4', end='\n')
def fun():
for i in range(800):
print('@', end='')
print('!', end='')
print('$', end='')
print('%', end='\n')
if __name__ == '__main__':
task1 = Process(target=study)
task2 = Process(target=speak)
task3 = Process(target=fun)
task3.start()
task1.start()
task2.start()
........
abcd
1abcd
23abc4d
a1b2c3d4
a1b234cd
a
b123c4
123d4
12
abcd3
abc4d
........python采用进程锁Lock/RLock来解决这个问题,lock.acquire()获取锁即获得执行权,其他线程进入等待,没获取到则一直等待直到获取锁,执行完成后lock.release()释放锁
python中acquire/release构成一个原子操作,也必须成对出现,否则会导致锁被一个进程一直持有程序中断
acquire/release可以配合上下文管理with来使用,效果相同更加简洁,异常了也能自动释放锁
from multiprocessing import Process, Lock
def study(lock):
for i in range(800):
try:
lock.acquire()
print('a', end='')
print('b', end='')
print('c', end='')
print('d')
finally:
lock.release()
def speak(lock):
for i in range(800):
with lock:
print('1', end='')
print('2', end='')
print('3', end='')
print('4')
def fun(lock):
for i in range(800):
with lock:
print('@', end='')
print('!', end='')
print('$', end='')
print('%')
if __name__ == '__main__':
lock = Lock()
task1 = Process(target=study, args=(lock,))
task2 = Process(target=speak, args=(lock,))
task3 = Process(target=fun, args=(lock,))
task3.start()
task1.start()
task2.start()❗Lock锁不可重复,重复加锁会导致第二次加锁时进入无限等待锁释放,造成死锁,比如一个加了Lock或with lock结构的函数中调用了同样有Lock或with lock结构的另一函数
解决这个问题,实际开发中常用支持计数的multiprocessing.RLock锁,用法相同
3.进程常见方法
3.1 join
join()方法,会阻塞当前调用join()方法的进程,等join前的进程执行完,再继续往下执行
a() {
//a方法在此处被阻塞了,而不是b被阻塞
b.join()
}只有已经start()的进程,才能join()
例:p1.join()导致主进程阻塞,p1执行后,p2才启动,p2.join()再次导致主进程阻塞,p2执行,然后主进程执行,两个子进程先后执行
if __name__ == '__main__':
print('主进程开始执行')
print('主进程 ', os.getpid())
p1 = Process(target=study)
p2 = Process(target=speak)
p1.start()
p1.join()
p2.start()
p2.join()
print('主进程结束执行')主进程开始执行
主进程 19424
<Process name='Process-1' parent=19424 started> 0 父进程 19424 进程 33352 Study
<Process name='Process-1' parent=19424 started> 1 父进程 19424 进程 33352 Study
<Process name='Process-1' parent=19424 started> 2 父进程 19424 进程 33352 Study
<Process name='Process-2' parent=19424 started> 0 父进程 19424 进程 25508 speak
<Process name='Process-2' parent=19424 started> 1 父进程 19424 进程 25508 speak
<Process name='Process-2' parent=19424 started> 2 父进程 19424 进程 25508 speak
主进程结束执行例:p1,p2同时启动后,再同时阻塞主进程,都执行完成后,然后主进程执行,两个子进程会交替执行
import os
import time
from multiprocessing import Process, current_process
def study():
for i in range(3):
print('%s %s 父进程 %s 进程 %s Study' % (current_process(), i, os.getppid(), os.getpid()) , end='\n')
time.sleep(1)
def speak():
for i in range(3):
print('%s %s 父进程 %s 进程 %s speak' % (current_process(), i, os.getppid(), os.getpid()) , end='\n')
time.sleep(1)
if __name__ == '__main__':
print('主进程开始执行')
print('主进程 ', os.getpid())
p1 = Process(target=study)
p2 = Process(target=speak)
p1.start()
p2.start()
p1.join()
p2.join()
print('主进程结束执行')
主进程开始执行
主进程 6568
<Process name='Process-1' parent=6568 started> 0 父进程 6568 进程 4684 Study
<Process name='Process-2' parent=6568 started> 0 父进程 6568 进程 6052 speak
<Process name='Process-1' parent=6568 started> 1 父进程 6568 进程 4684 Study
<Process name='Process-2' parent=6568 started> 1 父进程 6568 进程 6052 speak
<Process name='Process-1' parent=6568 started> 2 父进程 6568 进程 4684 Study
<Process name='Process-2' parent=6568 started> 2 父进程 6568 进程 6052 speak
主进程结束执行例:p1,p2同时启动后,仅p1阻塞主进程,p1,p2会同时执行,但是主进程会等p1执行完成后开始执行
import os
import time
from multiprocessing import Process, current_process
def study():
for i in range(3):
print('%s %s 父进程 %s 进程 %s Study' % (current_process(), i, os.getppid(), os.getpid()) , end='\n')
time.sleep(1)
def speak():
for i in range(5):
print('%s %s 父进程 %s 进程 %s speak' % (current_process(), i, os.getppid(), os.getpid()) , end='\n')
time.sleep(3)
if __name__ == '__main__':
print('主进程开始执行')
print('主进程 ', os.getpid())
p1 = Process(target=study)
p2 = Process(target=speak)
p1.start()
p2.start()
p1.join()
print('主进程结束执行')主进程开始执行
主进程 17316
<Process name='Process-1' parent=17316 started> 0 父进程 17316 进程 32520 Study
<Process name='Process-2' parent=17316 started> 0 父进程 17316 进程 15728 speak
<Process name='Process-1' parent=17316 started> 1 父进程 17316 进程 32520 Study
<Process name='Process-1' parent=17316 started> 2 父进程 17316 进程 32520 Study
<Process name='Process-2' parent=17316 started> 1 父进程 17316 进程 15728 speak
主进程结束执行
<Process name='Process-2' parent=17316 started> 2 父进程 17316 进程 15728 speak
<Process name='Process-2' parent=17316 started> 3 父进程 17316 进程 15728 speak
<Process name='Process-2' parent=17316 started> 4 父进程 17316 进程 15728 speakjoin方法可以传递一个timeout参数,单位是秒,代表等待多少秒就不等了
例:p1只阻塞主进程3秒,函数执行两秒后打印,第二次进入循环已经是4秒后,此时3秒定时到期,主线程已经执行过
import os
import time
from multiprocessing import Process, current_process
def study():
for i in range(5):
time.sleep(2)
print('%s %s 父进程 %s 进程 %s Study' % (current_process(), i, os.getppid(), os.getpid()) , end='\n')
if __name__ == '__main__':
print('主进程开始执行')
print('主进程 ', os.getpid())
p1 = Process(target=study)
p1.start()
p1.join(3)
print('主进程结束执行')
主进程开始执行
主进程 33136
<Process name='Process-1' parent=33136 started> 0 父进程 33136 进程 26276 Study
主进程结束执行
<Process name='Process-1' parent=33136 started> 1 父进程 33136 进程 26276 Study
<Process name='Process-1' parent=33136 started> 2 父进程 33136 进程 26276 Study
<Process name='Process-1' parent=33136 started> 3 父进程 33136 进程 26276 Study
<Process name='Process-1' parent=33136 started> 4 父进程 33136 进程 26276 Study3.2 terminate
terminate()用于向操作系统申请终止某个进程,是异步执行的,终止申请发送给操作系统,由操作系统决定什么时机终止,并非立即关闭
执行
terminate(),被终止进程运行中方法的finally语句不会执行
import os
import time
from multiprocessing import Process, current_process
from time import sleep
def study():
for i in range(5):
print('%s %s 父进程 %s 进程 %s Study' % (current_process(), i, os.getppid(), os.getpid()) , end='\n')
time.sleep(2)
def speak():
for i in range(5):
print('%s %s 父进程 %s 进程 %s speak' % (current_process(), i, os.getppid(), os.getpid()) , end='\n')
time.sleep(2)
if __name__ == '__main__':
print('主进程开始执行')
print('主进程 ', os.getpid())
p1 = Process(target=study, name='p1')
p2 = Process(target=speak, name='p2')
p1.start()
p2.start()
sleep(5)
p1.terminate()
print(p1.is_alive())
print('主进程结束执行')主进程开始执行
主进程 22236
<Process name='p1' parent=22236 started> 0 父进程 22236 进程 31636 Study
<Process name='p2' parent=22236 started> 0 父进程 22236 进程 20860 speak
<Process name='p1' parent=22236 started> 1 父进程 22236 进程 31636 Study
<Process name='p2' parent=22236 started> 1 父进程 22236 进程 20860 speak
<Process name='p1' parent=22236 started> 2 父进程 22236 进程 31636 Study
<Process name='p2' parent=22236 started> 2 父进程 22236 进程 20860 speak
True
主进程结束执行
<Process name='p2' parent=22236 started> 3 父进程 22236 进程 20860 speak
<Process name='p2' parent=22236 started> 4 父进程 22236 进程 20860 speak如需确认关闭成功再继续,可以终止前join一下
... ...
p1.terminate()
p1.join()
print(p1.is_alive()) # True4.守护进程
4.进程通信
5.进程池
"如果文章对您有帮助,可以请作者喝杯咖啡吗?"
微信支付
支付宝