多任务进程编程
进程实现多任务
定义
- 一个正在运行的程序或者软件就是一个进程
- 是操作系统进行资源分配的基本单位
python 使用的模块
创建进程
- multiprocessing 模块使用 Process 类创建进程实例对象,实现进程任务的创建
- Process([group [, target [, name [, args [, kwargs]]]]])
参数说明
- group:制定进程组,目前只能使用 None
- target:执行的任务目标名
- name:进程名字
- args:以元组方式给执行任务传参
- kwargs:以字典方式给执行任务传参
示例
import multiprocessing as mu
import time
# 跳舞任务
def task1():
for i in range(10):
print('task 1 run....')
print(time.time())
time.sleep(0.3)
# 唱歌任务
def task2():
for i in range(10):
print('task 2 run....')
print(time.time())
time.sleep(0.3)
# 程序入口
if __name__ == '__main__':
p1 = mu.Process(target=task1, name='My process1')
p2 = mu.Process(target=task2)
启动进程
- 进程对象创建成功后,需要启动才会执行
- p1.start()
- p2.start()
获取当前进程
- multiprocessing.current_process() 可以获取当前进程
def task1():
for i in range(3):
print('task 1 run.... ,获取当前进程', mu.current_process())
# task 1 run.... ,获取当前进程 <Process name='My process1' parent=12672 started>
time.sleep(0.3)
# 唱歌任务
def task2():
for i in range(3):
print('task 2 run.... ,获取当前进程', mu.current_process())
# task 2 run.... ,获取当前进程 <Process name='Process-4' parent=12672 started>
time.sleep(0.3)
获取进程名
def task1():
for i in range(3):
print('task 1 run.... ,获取当前进程', mu.current_process().name)
# task 1 run.... ,获取当前进程 My process1
time.sleep(0.3)
# 唱歌任务
def task2():
for i in range(3):
print('task 2 run.... ,获取当前进程', mu.current_process().name)
# task 2 run.... ,获取当前进程 Process-4
time.sleep(0.3)
获取进程 ID
- 每一个进程产生时,操作系统都会为进程分配一个 ID 编号,可以通过 os 模块中的方法获取进程的 ID
- os.getpid() 获取当前进程 ID
- os.getooid() 获取当前进程的父进程的 ID
def task1():
for i in range(2):
print(f'task 1 run...., 获取当前进程, {mu.current_process().name}_ID',os.getpid())
print(f'task 1 run...., 获取当前进程, {mu.current_process().name}_Parent_ID',os.getppid())
# task 1 run...., 获取当前进程, Process-1_ID 3916
# task 1 run...., 获取当前进程, Process-1_Parent_ID 1228
time.sleep(0.3)
# 唱歌任务
def task2():
for i in range(2):
print(f'task 2 run...., 获取当前进程, {mu.current_process().name}_ID',os.getpid())
print(f'task 2 run...., 获取当前进程, {mu.current_process().name}_Parent_ID',os.getppid())
# task 2 run...., 获取当前进程, Process-2_ID 12668
# task 2 run...., 获取当前进程, Process-2_Parent_ID 13380
time.sleep(0.3)
进程任务函数传参
- 在创建进程对象的时候,为进程任务函数传递参数,可以使用两种方法
- args:使用可变位置参数形式传参
- kwargs:使用可变关键字参数形式传参
def task1(n, msg):
for i in range(n):
print(mu.current_process().name, f'task1--打印第{i + 1} 次 {msg}')
time.sleep(0.3)
def creat_task():
p1 = mu.Process(target=task1, args=(3, 'tasssssk1'))
# 启动进程
p1.start()
print(f'{mu.current_process()}_父级_ID', os.getpid())
# 程序入口
if __name__ == '__main__':
creat_task()
# Process-1 task1--打印第1 次 tasssssk1
# Process-1 task1--打印第2 次 tasssssk1
# Process-1 task1--打印第3 次 tasssssk1
进程同步
- join() 方法用来将子进程添加到当前进程之前执行,直到子进程执行结束后,当前进程才会继续执行
- 多个进程间的代码运行时是交替执行的,如果使用 join() 方法后,当前进程会进入到阻塞状态,等待子进程执行完毕后才会解除阻塞状态,继续执行
- 使用 join() 方法后,可以使多进程的 异步执行 变成 同步执行 ,过多使用会使程序效率变低
def task1(n, msg):
for i in range(n):
print(mu.current_process().name, f'task1--打印第{i + 1} 次 {msg}')
time.sleep(0.3)
def creat_task():
p1 = mu.Process(target=task1, args=(3, 'tasssssk1'))
# 启动进程
p1.start()
p1.join()
print(f'执行父级任务,{mu.current_process()}_父级_ID', os.getpid())
# 程序入口
if __name__ == '__main__':
creat_task()
# Process-1 task1--打印第1 次 tasssssk1
# Process-1 task1--打印第2 次 tasssssk1
# Process-1 task1--打印第3 次 tasssssk1
# 执行父级任务,<_MainProcess name='MainProcess' parent=None started>_父级_ID 996
守护进程
- 多进程在执行时,父进程会等待子进程执行结束才会结束
- 如果需要子进程在父进程执行结束后就结束执行,无论子进程是否执行完毕,可以将子进程设置为守护进程
- 使用 子进程对象.daemon = Ture 在子进程启动前将子进程设置为守护进程
- 使用 子进程对象.terminate() 在主进程退出前手动将子进程结束
设置子进程为守护进程
import multiprocessing as mu
import os
import time
# 跳舞任务
def task1(n, msg):
for i in range(n):
print(mu.current_process().name, f'task1--打印第{i + 1} 次 {msg}')
time.sleep(0.3)
def task2(n, msg):
for i in range(n):
print(mu.current_process().name, f'task2--打印第{i + 1} 次 {msg}')
time.sleep(0.3)
def creat_task():
p1 = mu.Process(target=task1, args=(300, 'tasssssk1'))
p2 = mu.Process(target=task1, kwargs={"n": 20, "msg": "taaaaaask2"})
# 启动进程
print('父级任务开始')
print(f'执行父级任务,{mu.current_process()}_父级_ID', os.getpid())
# 将子进程设置为守护进程
p1.daemon = True
p2.daemon = True
p1.start()
p2.start()
time.sleep(0.5)
print("父级任务结束")
# 程序入口
if __name__ == '__main__':
creat_task()
# 父级任务开始
# 执行父级任务,<_MainProcess name='MainProcess' parent=None started>_父级_ID 9028
# Process-1 task1--打印第1 次 tasssssk1
# Process-2 task1--打印第1 次 taaaaaask2
# Process-1 task1--打印第2 次 tasssssk1
# Process-2 task1--打印第2 次 taaaaaask2
# 父级任务结束
手动杀死子进程
def creat_task():
p1 = mu.Process(target=task1, args=(300, 'tasssssk1'))
p2 = mu.Process(target=task1, kwargs={"n": 20, "msg": "taaaaaask2"})
# 启动进程
print('父级任务开始')
print(f'执行父级任务,{mu.current_process()}_父级_ID', os.getpid())
# 将子进程设置为守护进程
# p1.daemon = True
# p2.daemon = True
p1.start()
p2.start()
time.sleep(0.5)
# 手动杀死子进程实现守护效果
p1.terminate()
p2.terminate()
print("父级任务结束")
# 程序入口
if __name__ == '__main__':
creat_task()
# 父级任务开始
# 执行父级任务,<_MainProcess name='MainProcess' parent=None started>_父级_ID 7512
# Process-1 task1--打印第1 次 tasssssk1
# Process-2 task1--打印第1 次 taaaaaask2
# Process-1 task1--打印第2 次 tasssssk1
# Process-2 task1--打印第2 次 taaaaaask2
# 父级任务结束
进程间不共享全局变量
- 因为进程是程序执行的最小资源分配单位,当一个子进程被创建时,子进程会复制父进程的资源,形成一个独立的空间,所以多个子进程之间的数据是独立不共享的
import multiprocessing as mu
import os
import time
# 定义全局变量
g_list = list()
# 添加数据的任务
def add_data():
for i in range(3):
g_list.append(i)
print("add:",i)
time.sleep(0.2)
print("add_data:", g_list)
# add: 0
# add: 1
# add: 2
# add_data: [0, 1, 2]
def read_data():
print("read_data:",g_list)
# read_data: []
def creat_data():
p1 = mu.Process(target=add_data)
p2 = mu.Process(target=read_data)
p1.start()
p1.join()
p2.start()
print('creat_data:',g_list)
# creat_data: []
if __name__ == '__main__':
creat_data()
进程相关操作