多任务
1. 多任务
1. 概念:同一时间内执行多个任务。
2. 执行方式
- 并发:在一段时间内交替去执行任务。
- 并行:多核CPU是并行的执行多任务,始终有多个软件一起执行。只有多核CPU才能真正意义上让多个软件一起运行。
2. 进程
1. 概念:一个正在运行的程序或者软件就是一个进程,它是操作系统进行资源分配的基本单位。每启动一个进程,操作系统都会给其分配一定的运行资源(内存资源)保证进程的运行。
一个程序运行后至少有一个进程,一个进程默认有一个线程,进程里面可以创建多个线程,线程是依附在进程里面的,没有进程就没有线程。多进程可以完成多任务。
3. 多进程
1. 导入进程包
# 导入进程包
import multiprocessing
2. 语法
Process([group [, target [, name [, args [, kwargs]]]]])
- group:指定进程组,目前只能使用None
- target:执行的目标任务名
- name:进程名字
- args:以元组方式给执行任务传参
- kwargs:以字典方式给执行任务传参
Process创建的实例对象的常用方法:
- start():启动子进程实例(创建子进程)
- join():等待子进程执行结束
- terminate():不管任务是否完成,立即终止子进程
Process创建的实例对象的常用属性:
- name:当前进程的别名,默认为Process-N,N为从1开始递增的整数
3. 示例
import multiprocessing
import time
def prt_info1():
for i in range(3):
print("cb1")
time.sleep(0.3)
def prt_info2():
for i in range(3):
print("cb2")
time.sleep(0.3)
if __name__ == '__main__':
prt_info1_process = multiprocessing.Process(target=prt_info1)
prt_info1_process.start()
prt_info2_process = multiprocessing.Process(target=prt_info2)
prt_info2_process.start()
# 输出结果
cb2
cb1
cb2
cb1
cb2
cb1
4. 获取进程编号
1. 目的
验证主进程和子进程的关系,可以得知子进程是由哪个主进程创建出来的。
获取进程编号的两种操作:
- 获取当前进程编号
- 获取当前父进程编号
2. 获取当前进程编号
# 示例 - 1
# os.getpid() 表示获取当前进程编号
import multiprocessing
import time
import os
def prt_info1():
# 获取子进程编号
print("prt_info1_pid: ", os.getpid())
# 获取父进程编号
print("prt_info1_parent_pid: ", os.getppid())
# 当前进程名
print("prt_info1_process_name: ", multiprocessing.current_process())
for i in range(3):
print("cb1")
time.sleep(0.3)
def prt_info2():
# 获取子进程编号
print("prt_info2_pid: ", os.getpid())
# 获取父进程编号
print("prt_info2_parent_pid: ", os.getppid())
# 当前进程名
print("prt_info2_process_name: ", multiprocessing.current_process())
for i in range(3):
print("cb2")
time.sleep(0.3)
if __name__ == '__main__':
# 获取主进程编号
print("main_pid: ", os.getpid())
# 当前进程名
print("process_name: ", multiprocessing.current_process())
prt_info1_process = multiprocessing.Process(target=prt_info1)
prt_info1_process.start()
prt_info2_process = multiprocessing.Process(target=prt_info2)
prt_info2_process.start()
# 输出结果
main_pid: 4980
process_name: <_MainProcess name='MainProcess' parent=None started>
prt_info1_pid: 26380
prt_info1_parent_pid: 4980
prt_info1_process_name: <Process name='Process-1' parent=4980 started>
cb1
prt_info2_pid: 18488
prt_info2_parent_pid: 4980
prt_info2_process_name: <Process name='Process-2' parent=4980 started>
cb2
cb1
cb2
cb1
cb2
# 示例 - 2
import multiprocessing
import time
import os
def prt_info1():
# 获取子进程编号
print("prt_info1_pid: ", os.getpid())
# 获取父进程编号
print("prt_info1_parent_pid: ", os.getppid())
# 当前进程名
print("prt_info1_process_name: ", multiprocessing.current_process())
for i in range(3):
print("cb1")
time.sleep(0.3)
# 根据进程编号杀死进程,9为强制杀死
os.kill(os.getpid(), 9)
def prt_info2():
# 获取子进程编号
print("prt_info2_pid: ", os.getpid())
# 获取父进程编号
print("prt_info2_parent_pid: ", os.getppid())
# 当前进程名
print("prt_info2_process_name: ", multiprocessing.current_process())
for i in range(3):
print("cb2")
time.sleep(0.3)
if __name__ == '__main__':
# 获取主进程编号
print("main_pid: ", os.getpid())
# 当前进程名
print("process_name: ", multiprocessing.current_process())
prt_info1_process = multiprocessing.Process(target=prt_info1)
prt_info1_process.start()
prt_info2_process = multiprocessing.Process(target=prt_info2)
prt_info2_process.start()
# 输出结果
main_pid: 25160
process_name: <_MainProcess name='MainProcess' parent=None started>
prt_info1_pid: 16012
prt_info1_parent_pid: 25160
prt_info1_process_name: <Process name='Process-1' parent=25160 started>
cb1
prt_info2_pid: 10396
prt_info2_parent_pid: 25160
prt_info2_process_name: <Process name='Process-2' parent=25160 started>
cb2
cb2
cb2
3. 进程执行带有参数的任务
import multiprocessing
def prt_name(name):
print(name)
if __name__ == '__main__':
prt_name_process = multiprocessing.Process(target=prt_name, args=("cb", ))
prt_name_process.start()
# 输出结果
cb
4. 进程的注意点
1. 注意点
- 进程之间不共享全局变量
- 创建子进程其实是对主进程资源进行拷贝,子进程其实就是主进程的一个副本。
import multiprocessing import time lst_num = list() # -> [] # 写入数据 def write_num(): for i in range(3): # 因为列表是可变类型,可以在原有内存的基础上修改数据,并且修改后内存地址不变 # 所以不需要加上global关键字 # 加上global表示声明要修改全局变量的内存地址 lst_num.append(i) time.sleep(0.3) print(multiprocessing.current_process(), ": ", i) # 读取数据 def read_num(): for i in range(3): print(multiprocessing.current_process(), ": ", lst_num) time.sleep(0.3) # 对于Linux和mac主进程执行的代码不会进行进程拷贝,但是对于window系统主进程执行的代码也会进行拷贝 # 对应window来说创建子进程的代码如果进程拷贝执行相当于递归无限制进行创建子进程,会报错,所以在创建进程的地方需要加上if __name__ == '__main__': # 直接执行的模块就是主模块,直接执行的模块里面就应该添加判断是否是主模块的代码 # if __name__ == '__main__':的两种作用 # 1. 防止别人导入模块的时候执行main里面的代码 # 2. 防止window系统递归创建子进程 if __name__ == '__main__': write_num_process = multiprocessing.Process(target=write_num) read_num_process = multiprocessing.Process(target=read_num) write_num_process.start() # 当前进程(主进程)等待添加数据的进程执行完成以后代码再继续往下执行 write_num_process.join() read_num_process.start() # 输出结果 <Process name='Process-1' parent=34524 started> : 0 <Process name='Process-1' parent=34524 started> : 1 <Process name='Process-1' parent=34524 started> : 2 <Process name='Process-2' parent=34524 started> : [] <Process name='Process-2' parent=34524 started> : [] <Process name='Process-2' parent=34524 started> : []
- 主进程会等待所有的子进程执行结束再结束
import multiprocessing import time def work(): for i in range(5): print("working……") time.sleep(0.2) if __name__ == '__main__': work_process = multiprocessing.Process(target=work) work_process.start() time.sleep(0.5) print("end") # 输出结果 working…… working…… end working…… working…… working……
- 子进程守护主进程
import multiprocessing import time def work(): for i in range(5): print("working……") time.sleep(0.2) if __name__ == '__main__': work_process = multiprocessing.Process(target=work) # 解决子进程死循环主进程无法结束:主进程退出子进程销毁 # 1. 让子进程设置成为守护主进程,主进程退出子进程销毁,子进程依赖主进程 # 2. 让主进程退出之前先让子进程销毁 work_process.daemon = True work_process.start() time.sleep(0.5) print("end") # 输出结果 working…… working…… end
- 退出主进程之前先让子进程销毁
import multiprocessing import time def work(): for i in range(5): print("working……") time.sleep(0.2) if __name__ == '__main__': work_process = multiprocessing.Process(target=work) work_process.start() time.sleep(0.5) work_process.terminate() print("end") # 输出结果 working…… working…… end