多任务的执行方式
1.并发 (交替运行)
2.并行 (同时运行)
任务数大于内核数 并发执行
任务数小于等于内核数 并行执行
图片
进程的介绍
在Python程序中,想要实现多任务可以使用进程来完成,进程是实现多任务的一种方式。
图片
进程的概念
图片
一个正在运行的程序或者软件就是一个进程,它是操作系统进行资源分配的基本单位,也就是说每启
动一个进程,操作系统都会给其分配一定的运行资源(内存资源)
保证进程的运行。
进程,一个进程默认有一个线程,进程里面可以创建多个线程,
线程是依附在进程里面的,没有进程就没有线程。
多进程的使用
导入进程包
import multiprocessing
import time
跳舞任务
def dance():
for i in range(5):
print("跳舞中...")
time.sleep(0.2)
唱歌任务
def sing():
for i in range(5):
print("唱歌中...")
time.sleep(0.2)
if name == '__main__':
# 创建跳舞的子进程
# group: 表示进程组,目前只能使用None
# target: 表示执行的目标任务名(函数名、方法名)
# name: 进程名称, 默认是Process-1, .....
dance_process = multiprocessing.Process(group=None, target=dance, name= "myprogress1")
sing_process = multiprocessing.Process(target=sing)
# 启动子进程执行对应的任务
dance_process.start()
sing_process.start()
获取进程编号
导入进程包
import multiprocessing
import time
import os
跳舞任务
def dance():
# 获取当前进程(子进程)编号
dance_process_pid = os.getpid()
print("dance_process_pid:", dance_process_pid, multiprocessing.current_process())
# 获取当前进程的父进程编号
dance_process_parent_pid = os.getppid()
print("dance_process的父进程编号是:", dance_process_parent_pid)
for i in range(5):
print("跳舞中...")
time.sleep(0.2)
# 扩展:根据进程编号强制杀死指定进程
os.kill(dance_process_pid, 9)
唱歌任务
def sing():
sing_process_parent_pid = os.getppid()
print("sing_process_parent_pid的父进程编号是:", sing_process_parent_pid)
for i in range(5):
print("唱歌中...")
time.sleep(0.2)
获取当前进程(主进程)编号
main_process_pid = os.getpid()
print("main_process_id:", main_process_pid, multiprocessing.current_process())
if name == '__main__':
# 创建跳舞的子进程
# group: 表示进程组,目前只能使用None
# target: 表示执行的目标任务名(函数名、方法名)
# name: 进程名称, 默认是Process-1, .....
dance_process = multiprocessing.Process(group=None, target=dance, name= "my_process1")
sing_process = multiprocessing.Process(target=sing, name='my_process2')
# 启动子进程执行对应的任务
dance_process.start()
sing_process.start()
进程执行中带有参数
Progress类执行任务并给任务传参数有两种方式:
. args表示以元组的方式给执行任务传参
. kwargs表示以字典方式给执行任务传参
import multiprocessing
显示任务
def show_info(name, age):
print(name, age)
创建子进程
以元组方式传参,元组里面的元素顺序要和函数里面的参数顺序保持一致
sub_process = multiprocessing.Process(target=show_info, args=("hekang", 22))
sub_process = multiprocessing.Process(target=show_info, kwargs={'name':'杨凯文', 'age': 20})
以字典方式传参,字典里面的key要和函数里面的参数名保持一致,没有顺序要求
启动进程
if name == '__main__':
sub_process.start()
一个参数用元组传,一个参数用字典传
sub_process = multiprocessing.Process(target=show_info, args=("hekang",), kwargs={"age"=22}
进程之间不共享全局变量
import multiprocessing
import time
g_list = list() # => []
添加数据
def add_data():
for i in range(3):
# 因为列表是可变类型,可以在原有内存的基础上修改数据,并且修改后内存地址不变
# 所以不需要加global 申明
# 加上global 表示申明要修改全局变量的内存地址
g_list.append(i)
print("added:", i)
time.sleep(0.2)
读取数据
def read_data():
print(g_list)
添加数据的子进程
add_process = multiprocessing.Process(target=add_data)
读取数据的子进程
read_process = multiprocessing.Process(target=read_data)
if name == '__main__':
add_process.start()
read_process.start()
运行结果
added: 0
[]
added: 1
added: 2
遇到一个不太理解的Tracedback
当上面的代码
if name == '__main__':
add_process.start()
read_process.start()
将if name == '__main__':
去掉调用的时候报错
RuntimeError:
An attempt has been made to start a new process before the
current process has finished its bootstrapping phase.
This probably means that you are not using fork to start your
child processes and you have forgotten to use the proper idiom
in the main module:
if __name__ == '__main__':
freeze_support()
...
The "freeze_support()" line can be omitted if the program
is not going to be frozen to produce an executable.
简单翻译下:
RuntimeError:
在当前进程完成了他的引导阶段之前试图去启动一个新进程。
这可能是表示你没有用fork方法启动子进程,并且你忘了用正确的姿势在main模块中:
if name == '__main__':
freeze_support()
...
如果程序不会被冻结以生成可执行文件The "freeze_support()" 这行代码可以被忽略
至于具体为什么,根本原因,也没完全理解,大致就是windows创建进程没有fork方法,默认是spawn,而linux创建进程默认是fork方法。为了什么进程保护,代码必须放在if name == '__main__':下面。想要完全理解估计还要深入理解进程的概念,什么僵尸进程,孤儿进程类吧。
解决方法
加 if name == '__main__':