一、多任务
概述:
多任务指的是 多个任务同时进行。
目的:
节约资源,充分利用CPU资源,提高效率。
表现形式:
并发:针对于单核CPU来讲的,如果有多个任务同时请求执行,当时同一瞬间CPU只能执行1个任务,于是就安排它们交替执行.因为时间间额非常短(CPU执行速度太快了),我们看起来好像是同时执行的,实际上并不是。
并行:针对多核CPU来讲的,多个任务可以同时执行。
进程介绍:
概述:
进程:指的是 可执行程序,是CPU分配资源的最小单位。
线程:进程的执行路径,执行单元。
通俗解释:
进程:车 线程:车道
多进程实现步骤:
1.导包
2.创建进程对象,关联:该进程要执行的任务。
3.启动进程
二、单进程程序
只有前边的内容执行结束之后,才会执行后续的内容,相对耗时,且没有做到资源的合理利用。
示例代码:
python
"""
案例:
回顾单进程程序, 即: 以前写的代码都是单进程的, 只有前边的内容执行结束后, 才会执行后续会的内容, 相对耗时, 且没有做到资源的合理利用.
"""
import time
# 需求: 模拟一遍写代码, 一遍听音乐.
# 1. 定义函数, 表示: 写代码.
def coding():
for i in range(1, 11):
time.sleep(0.1)
print(f"正在写代码... {i}")
# 2. 定义函数, 表示: 听音乐.
def music():
for i in range(1, 11):
time.sleep(0.1)
print(f"正在听音乐------ {i}")
# 3. 在main函数中测试.
if __name__ == '__main__':
# 4. 模拟单进程程序.
coding()
music()
运行结果:
正在写代码... 1
正在写代码... 2
正在写代码... 3
正在写代码... 4
正在写代码... 5
正在写代码... 6
正在写代码... 7
正在写代码... 8
正在写代码... 9
正在写代码... 10
正在听音乐------ 1
正在听音乐------ 2
正在听音乐------ 3
正在听音乐------ 4
正在听音乐------ 5
正在听音乐------ 6
正在听音乐------ 7
正在听音乐------ 8
正在听音乐------ 9
正在听音乐------ 10
三、多进程程序
示例代码:
python
"""
案例:
回顾单进程程序, 即: 以前写的代码都是单进程的, 只有前边的内容执行结束后, 才会执行后续会的内容, 相对耗时, 且没有做到资源的合理利用.
多进程的实现步骤:
1. 导包
2. 创建进程对象, 关联: 要执行的函数.
3. 启动进程.
"""
import multiprocessing, time
# 需求: 模拟一遍写代码, 一遍听音乐.
# 1. 定义函数, 表示: 写代码.
def coding():
for i in range(1, 21):
# 为了让效果更明显, 加入: 休眠线程.
time.sleep(0.01)
print(f"正在写代码... {i}", end='\n')
# 2. 定义函数, 表示: 听音乐.
def music():
for i in range(1, 21):
# 为了让效果更明显, 加入: 休眠线程.
time.sleep(0.01)
print(f"正在听音乐------ {i}")
# 3. 在main函数中测试.
if __name__ == '__main__':
# 4. 创建两个进程对象, 分别关联上述的两个函数.
p1 = multiprocessing.Process(target=coding)
p2 = multiprocessing.Process(target=music)
# 5. 启动进程.
p1.start()
p2.start()
运行结果:
正在听音乐------ 1
正在写代码... 1
正在听音乐------ 2
正在写代码... 2
正在听音乐------ 3
正在写代码... 3
正在听音乐------ 4
正在写代码... 4
正在听音乐------ 5
正在写代码... 5
正在听音乐------ 6
正在写代码... 6
正在听音乐------ 7
正在写代码... 7
正在听音乐------ 8
正在写代码... 8
正在听音乐------ 9
正在写代码... 9
正在听音乐------ 10
正在写代码... 10
正在听音乐------ 11
正在写代码... 11
正在听音乐------ 12
正在写代码... 12
正在听音乐------ 13
正在写代码... 13
正在听音乐------ 14
正在写代码... 14
正在听音乐------ 15
正在写代码... 15
正在听音乐------ 16
正在写代码... 16
正在听音乐------ 17
正在写代码... 17
正在听音乐------ 18
正在写代码... 18
正在听音乐------ 19
正在写代码... 19
正在听音乐------ 20
正在写代码... 20
四、带参数的多进程程序
python
"""
案例:
回顾单进程程序, 即: 以前写的代码都是单进程的, 只有前边的内容执行结束后, 才会执行后续会的内容, 相对耗时, 且没有做到资源的合理利用.
多进程的实现步骤:
1. 导包
2. 创建进程对象, 关联: 要执行的函数.
3. 启动进程.
进程的参数解释, 即: multiprocessing模块的 Process类的 的参数:
target: 用于关联 进程要执行的任务的.
name: 进程名, 默认是: Process-1, Process-2,......Process-n, 可以手动修改, 一般不改.
args: 可以通过 元组 的形式传递参数, 实参的个数 及 对应的数据类型 要和 形参的个数及类型 一致.
kwargs: 可以通过 字典 的形式传递参数, 实参的个数 要和 形参的个数 一致.
"""
import multiprocessing, time
# 需求: 使用多进程来模拟小明一边写num行代码, 一边听count首音乐.
# 1. 小明写num行代码
def code(name, num):
for i in range(1, num):
# 为了让效果更明显, 加入: 休眠线程.
time.sleep(0.01)
print(f"{name} 正在写第 {i} 行代码... ")
# 2. 小明听count首音乐
def music(name, count):
for i in range(1, count):
# 为了让效果更明显, 加入: 休眠线程.
time.sleep(0.01)
print(f"{name} 正在听第 {i} 首音乐------ ")
# 3. 在main函数中编写测试代码.
if __name__ == '__main__':
# 4. 创建进程对象.
p1 = multiprocessing.Process(target=code, args=("小明", 20), name='QQ进程')
# print(f'p1进程的名字: {p1.name}')
p2 = multiprocessing.Process(target=music, kwargs={'count': 20, 'name': '小明'}, name='微信进程')
# print(f'p2进程的名字: {p2.name}')
# 5. 启动进程.
p1.start()
p2.start()
运行结果:
小明 正在写第 1 行代码...
小明 正在写第 2 行代码...
小明 正在听第 1 首音乐------
小明 正在写第 3 行代码...
小明 正在听第 2 首音乐------
小明 正在写第 4 行代码...
小明 正在听第 3 首音乐------
小明 正在写第 5 行代码...
小明 正在听第 4 首音乐------
小明 正在写第 6 行代码...
小明 正在听第 5 首音乐------
小明 正在写第 7 行代码...
小明 正在听第 6 首音乐------
小明 正在写第 8 行代码...
小明 正在听第 7 首音乐------
小明 正在写第 9 行代码...
小明 正在听第 8 首音乐------
小明 正在写第 10 行代码...
小明 正在听第 9 首音乐------
小明 正在写第 11 行代码...
小明 正在听第 10 首音乐------
小明 正在写第 12 行代码...
小明 正在听第 11 首音乐------
小明 正在写第 13 行代码...
小明 正在听第 12 首音乐------
小明 正在写第 14 行代码...
小明 正在听第 13 首音乐------
小明 正在写第 15 行代码...
小明 正在听第 14 首音乐------
小明 正在写第 16 行代码...
小明 正在听第 15 首音乐------
小明 正在写第 17 行代码...
小明 正在听第 16 首音乐------
小明 正在写第 18 行代码...
小明 正在听第 17 首音乐------
小明 正在写第 19 行代码...
小明 正在听第 18 首音乐------
小明 正在听第 19 首音乐------
五、获取进程的id
python
"""
案例:
获取进程的id
进程的ID介绍:
概述:
在操作系统中, 每个进程都有自己唯一的ID, 且当前进程被终止时, 该ID会被回收, 即: ID是可以重复使用的.
目的:
1. 查找子进程是由那个父进程创建的, 即: 找子进程和父进程的ID.
2. 方便我们维护进程, 例如: kill -9 pid值 可以强制杀死进程.
获取进程id的方式:
获取当前进程的ID:
方式1: os模块的 getpid()方法
方式2: multiprocessing模块的 pid属性
获取当前进程的父进程的pid:
os模块的 getppid()方法 parent process: 父进程
结论:
我们看到 p1, p2进程的父进程是main, main进程的父进程是Pycharm.exe
"""
# 导包
import multiprocessing, time, os
# 案例: 小明一边敲着第n行代码, 一边听着第n首音乐.
# 1. 定义函数, 表示: 敲代码.
def code(name, num):
for i in range(1, num + 1):
print(f'{name} 正在敲第 {i} 行代码...')
time.sleep(0.1)
# multiprocessing模块的current_process()函数: 获取当前进程对象
print(f'当前进程(p1)的id: {os.getpid()}, {multiprocessing.current_process().pid}, 父进程的id为: {os.getppid()}')
# 2. 定义函数, 表示: 听音乐
def music(name, count):
for i in range(1, count + 1):
print(f'{name} 正在听第 {i} 首音乐.........')
time.sleep(0.1)
print(f'当前进程(p2)的id: {os.getpid()}, {multiprocessing.current_process().pid}, 父进程的id为: {os.getppid()}')
# 在main中测试.
if __name__ == '__main__':
# 3. 创建进程对象.
# Process类的参数: target: 关联的函数名, name: 当前进程的名字, args:元组的形式传参. kwargs: 字典的形式传参.
p1 = multiprocessing.Process(name='Process_QQ', target=code, args=('乔峰', 10))
p2 = multiprocessing.Process(name='Process_Wechat', target=music, kwargs={'count': 10, 'name': '虚竹'})
# print(f"p1进程的名字: {p1.name}")
# print(f"p2进程的名字: {p2.name}")
# 4. 启动进程.
p1.start()
p2.start()
print(f'当前进程(main)的id: {os.getpid()}, {multiprocessing.current_process().pid}, 父进程的id为: {os.getppid()}')
运行结果:
当前进程(main)的id: 37732, 37732, 父进程的id为: 42048
乔峰 正在敲第 1 行代码...
虚竹 正在听第 1 首音乐.........
当前进程(p1)的id: 44724, 44724, 父进程的id为: 37732
乔峰 正在敲第 2 行代码...
当前进程(p2)的id: 46024, 46024, 父进程的id为: 37732
虚竹 正在听第 2 首音乐.........
当前进程(p1)的id: 44724, 44724, 父进程的id为: 37732
乔峰 正在敲第 3 行代码...
当前进程(p2)的id: 46024, 46024, 父进程的id为: 37732
虚竹 正在听第 3 首音乐.........
当前进程(p1)的id: 44724, 44724, 父进程的id为: 37732
乔峰 正在敲第 4 行代码...
当前进程(p2)的id: 46024, 46024, 父进程的id为: 37732
虚竹 正在听第 4 首音乐.........
当前进程(p1)的id: 44724, 44724, 父进程的id为: 37732
乔峰 正在敲第 5 行代码...
当前进程(p2)的id: 46024, 46024, 父进程的id为: 37732
虚竹 正在听第 5 首音乐.........
当前进程(p1)的id: 44724, 44724, 父进程的id为: 37732
乔峰 正在敲第 6 行代码...
当前进程(p2)的id: 46024, 46024, 父进程的id为: 37732
虚竹 正在听第 6 首音乐.........
当前进程(p1)的id: 44724, 44724, 父进程的id为: 37732
乔峰 正在敲第 7 行代码...
当前进程(p2)的id: 46024, 46024, 父进程的id为: 37732
虚竹 正在听第 7 首音乐.........
当前进程(p1)的id: 44724, 44724, 父进程的id为: 37732
乔峰 正在敲第 8 行代码...
当前进程(p2)的id: 46024, 46024, 父进程的id为: 37732
虚竹 正在听第 8 首音乐.........
当前进程(p1)的id: 44724, 44724, 父进程的id为: 37732
乔峰 正在敲第 9 行代码...
当前进程(p2)的id: 46024, 46024, 父进程的id为: 37732
虚竹 正在听第 9 首音乐.........
当前进程(p1)的id: 44724, 44724, 父进程的id为: 37732
乔峰 正在敲第 10 行代码...
当前进程(p2)的id: 46024, 46024, 父进程的id为: 37732
虚竹 正在听第 10 首音乐.........
当前进程(p1)的id: 44724, 44724, 父进程的id为: 37732
当前进程(p2)的id: 46024, 46024, 父进程的id为: 37732
六、进程之间数据相互隔离
python
"""
案例:
演示进程之间数据是相互隔离的.
关于进程, 你要记忆的内容:
1. 进程之间数据是相互隔离的. 例如: 微信(进程) 和 QQ(进程)之间, 数据就是相互隔离的.
2. 默认情况下, 主进程会等待它所有的子进程 执行结束再结束.
细节:
多进程之间, 针对于 main进程的(外部资源), 每个子进程都会拷贝一份, 进行执行.
"""
import multiprocessing, time
# 需求: 定义1个列表, 然后定义两个函数, 分别往列表中添加数据, 获取数据. 之后用两个进程关联这个两个函数, 启动进程并观察结果.
# 1. 定义全局变量 my_list
my_list = []
print('我是main外资源, 看看我执行了几遍!')
# 2. 定义函数, 实现往列表中添加数据.
def write_data():
for i in range(1, 6):
# 具体的添加元素的动作
my_list.append(i)
# 打印添加动作.
print(f'添加 {i} 成功!')
# 细节: 添加数据完毕后, 打印结果.
print(f'write_data函数: {my_list}')
# 3. 定义函数, 实现从列表中获取数据.
def read_data():
# 休眠 3 秒, 确保 write_data函数执行完毕.
time.sleep(3)
# 打印结果.
print(f'read_data函数: {my_list}')
# 在main中测试
if __name__ == '__main__':
# 4. 创建进程对象.
p1 = multiprocessing.Process(target=write_data)
p2 = multiprocessing.Process(target=read_data)
# 5. 启动进程
p1.start()
p2.start()
# print('我是main内资源, 看看我执行了几遍!')
运行结果:
我是main外资源, 看看我执行了几遍!
我是main外资源, 看看我执行了几遍!
我是main外资源, 看看我执行了几遍!
添加 1 成功!
添加 2 成功!
添加 3 成功!
添加 4 成功!
添加 5 成功!
write_data函数: [1, 2, 3, 4, 5]
read_data函数: []
七、主进程和子进程的生命周期
示例代码一:
python
"""
案例:
演示 主进程 和 子进程的 生命周期.
结论:
1. 进程之间数据是相互隔离的. 例如: 微信(进程) 和 QQ(进程)之间, 数据就是相互隔离的.
2. 默认情况下, 主进程会等待它所有的子进程 执行结束再结束.
问: 如果要实现主进程结束时, 子进程也同步结束, 怎么办?
答:
1. 设置子进程为 守护进程. 类似于: 骑士(守护) 和 公主(非守护)
2. 手动关闭子进程.
"""
import multiprocessing, time
# 需求: 设置子进程执行3秒, 主进程执行1秒, 观察效果.
# 1. 定义方法, 用于关联子进程的.
def my_method():
for i in range(10):
print(f'工作中... {i}')
time.sleep(0.3) # 总休眠时间 = 0.3 * 10 = 3秒
# 2. 在main方法中测试.
if __name__ == '__main__':
# 3. 创建子进程对象, 并启动.
p1 = multiprocessing.Process(target=my_method)
p1.start() # 3秒后结束.
# 4. 主进程执行1秒后结束.
time.sleep(1)
# 5. 打印主进程的结束提示.
print('主进程 main 执行结束!')
运行结果:
工作中... 0
工作中... 1
工作中... 2
主进程 main 执行结束!
工作中... 3
工作中... 4
工作中... 5
工作中... 6
工作中... 7
工作中... 8
工作中... 9
示例代码二:
python
"""
案例:
演示 主进程 和 子进程的 生命周期.
结论:
1. 进程之间数据是相互隔离的. 例如: 微信(进程) 和 QQ(进程)之间, 数据就是相互隔离的.
2. 默认情况下, 主进程会等待它所有的子进程 执行结束再结束.
问: 如果要实现主进程结束时, 子进程也同步结束, 怎么办?
答:
1. 设置子进程为 守护进程. 类似于: 骑士(守护) 和 公主(非守护)
2. 手动关闭子进程.
"""
import multiprocessing, time
# 需求: 设置子进程执行3秒, 主进程执行1秒, 观察效果.
# 1. 定义方法, 用于关联子进程的.
def my_method():
for i in range(10):
print(f'工作中... {i}')
time.sleep(0.3) # 总休眠时间 = 0.3 * 10 = 3秒
# 2. 在main方法中测试.
if __name__ == '__main__':
# 3. 创建子进程对象, 并启动.
p1 = multiprocessing.Process(target=my_method)
# 方式1: 设置子进程p1为守护进程, 非守护进程是: main进程, 所以: 当main进程关闭的时候, 它的守护进程也会关闭.
# p1.daemon = True
p1.start() # 3秒后结束.
# 4. 主进程执行1秒后结束.
time.sleep(1)
# 方式2: 手动关闭子进程.
# 会导致子进程变成僵尸进程, 即: 不会立即释放资源.
# 而是交由init进程接管(充当新的父进程), 在合适的时机释放资源.
p1.terminate() # 不推荐使用.
# 5. 打印主进程的结束提示.
print('主进程 main 执行结束!')
运行结果:
工作中... 0
工作中... 1
工作中... 2
主进程 main 执行结束!