多任务编程
一、多任务的介绍
1、多任务的概念
多任务是指在同一时间内执行多个任务,例如: 现在电脑安装的操作系统都是多任务操作系统,可以同时运行着多个软件。
2、多任务的执行方式
- 并发:对于单核cpu处理多任务,操作系统轮流让各个软件交替执行,单核cpu是并发的执行多任务的。
- 并行: 对于多核cpu处理多任务,操作系统会给cpu的每个内核安排一个执行的软件,多个内核是真正的一起执行软件。这里需要注意多核cpu是并行的执行多任务,始终有多个软件一起执行。
二、进程
一个正在运行的程序或者软件就是一个进程,它是操作系统进行资源分配的基本单位,也就是说每启动一个进程,操作系统都会给其分配一定的运行资源(内存资源)保证进程的运行。
一个程序运行后至少有一个进程,一个进程默认有一个线程,进程里面可以创建多个线程,线程是依附在进程里面的,没有进程就没有线程。
1、多进程的使用
1 导入进程包
#导入进程包
import multiprocessing
2. Process进程类的说明
Process([group [, target [, name [, args [, kwargs]]]]])
group:指定进程组,目前只能使用None
target:执行的目标任务名
name:进程名字
args:以元组方式给执行任务传参
kwargs:以字典方式给执行任务传参
Process创建的实例对象的常用方法:
start():启动子进程实例(创建子进程)
join():等待子进程执行结束
terminate():不管任务是否完成,立即终止子进程
Process创建的实例对象的常用属性:
name:当前进程的别名,默认为Process-N,N为从1开始递增的整数
2、获取进程编号
获取进程编号的目的是验证主进程和子进程的关系,可以得知子进程是由那个主进程创建出来的。
获取进程编号的两种操作
- 获取当前进程编号:os.getpid() 表示获取当前进程编号
- 获取当前父进程编号:os.getppid() 表示获取当前父进程编号
- 获取进程编号可以查看父子进程的关系
3、进程执行带有参数的任务
import multiprocessing
import time
def sing(num, name):
for i in range(num):
time.sleep(1)
print("唱歌")
time.sleep(1)
print(name)
def dance(num, name):
for i in range(num):
time.sleep(1)
print("跳舞")
time.sleep(1)
print(name)
if __name__ == '__main__':
# 给进程执行的任务传参
# 通过args去传参 : 元组的形式传参
sing_process = multiprocessing.Process(target=sing, args=(3, "老王"))
# 通过kwargs传参 : 字典的形式传参
# 字典里的key值必须和函数的形参一致
dance_process = multiprocessing.Process(target=dance, kwargs={"num": 3, "name": "老李"})
sing_process.start()
dance_process.start()
4、进程的注意点
进程之间不共享全局变量
import multiprocessing
import time
# 定义全局变量
g_list = list()
# 添加数据的任务
def add_data():
for i in range(5):
g_list.append(i)
print("add:", i)
time.sleep(0.2)
# 代码执行到此,说明数据添加完成
print("add_data:", g_list)
def read_data():
print("read_data", g_list)
if __name__ == '__main__':
# 创建添加数据的子进程
add_data_process = multiprocessing.Process(target=add_data)
# 创建读取数据的子进程
read_data_process = multiprocessing.Process(target=read_data)
# 启动子进程执行对应的任务
add_data_process.start()
# 主进程等待添加数据的子进程执行完成以后程序再继续往下执行,读取数据
add_data_process.join()
read_data_process.start()
print("main:", g_list)
# 总结: 多进程之间不共享全局变量
主进程会等待所有的子进程执行结束再结束
import multiprocessing
import time
# 定义进程所需要执行的任务
def task():
for i in range(10):
print("任务执行中...")
time.sleep(0.2)
if __name__ == '__main__':
# 创建子进程
sub_process = multiprocessing.Process(target=task)
sub_process.start()
# 主进程延时0.5秒钟
time.sleep(0.5)
print("over")
exit()
# 总结: 主进程会等待所有的子进程执行完成以后程序再退出
三、线程
线程是进程中执行代码的一个分支,每个执行分支(线程)要想工作执行代码需要cpu进行调度 ,也就是说线程是cpu调度的基本单位,每个进程至少都有一个线程,而这个线程就是我们通常说的主线程。
1、多线程的使用
1. 导入线程模块
#导入线程模块
import threading
2. 线程类Thread参数说明
Thread([group [, target [, name [, args [, kwargs]]]]])
group: 线程组,目前只能使用None
target: 执行的目标任务名
args: 以元组的方式给执行任务传参
kwargs: 以字典方式给执行任务传参
name: 线程名,一般不用设置
3. 启动线程
启动线程使用start方法
2、线程执行带有参数的任务
import time
# 导入多线程的模块
import threading
def sing(num, name):
for _ in range(num):
time.sleep(0.5)
print(name)
def dance(num, name):
for _ in range(num):
time.sleep(0.5)
print(name)
if __name__ == '__main__':
# Process: 创建进程
# 参数1: target 进程要执行的任务 ==> 任务往往用函数名来表示
sing_thread = threading.Thread(target=sing, args=(3, "老王"))
dance_thread = threading.Thread(target=dance, kwargs={"num": 3, "name": "老李"})
# 启动进程
sing_thread.start()
dance_thread.start()
3、线程的注意点
- 线程之间执行是无序的
import threading
import time
def task():
time.sleep(1)
print("当前线程:", threading.current_thread().name)
if __name__ == '__main__':
for _ in range(5):
sub_thread = threading.Thread(target=task)
sub_thread.start()
- 主线程会等待所有的子线程执行结束再结束
import threading
import time
# 测试主线程是否会等待子线程执行完成以后程序再退出
def show_info():
for i in range(5):
print("test:", i)
time.sleep(0.5)
if __name__ == '__main__':
sub_thread = threading.Thread(target=show_info)
sub_thread.start()
# 主线程延时1秒
time.sleep(1)
print("over")
- 线程之间共享全局变量
import threading
import time
# 定义全局变量
my_list = list()
# 写入数据任务
def write_data():
for i in range(5):
my_list.append(i)
time.sleep(0.1)
print("write_data:", my_list)
# 读取数据任务
def read_data():
print("read_data:", my_list)
if __name__ == '__main__':
# 创建写入数据的线程
write_thread = threading.Thread(target=write_data)
# 创建读取数据的线程
read_thread = threading.Thread(target=read_data)
write_thread.start()
# 延时
# time.sleep(1)
# 主线程等待写入线程执行完成以后代码在继续往下执行
write_thread.join()
print("开始读取数据啦")
read_thread.start()
- 线程之间共享全局变量数据出现错误问题
import threading
# 定义全局变量
g_num = 0
# 循环一次给全局变量加1
def sum_num1():
for i in range(1000000):
global g_num
g_num += 1
print("sum1:", g_num)
# 循环一次给全局变量加1
def sum_num2():
for i in range(1000000):
global g_num
g_num += 1
print("sum2:", g_num)
if __name__ == '__main__':
# 创建两个线程
first_thread = threading.Thread(target=sum_num1)
second_thread = threading.Thread(target=sum_num2)
# 启动线程
first_thread.start()
# 启动线程
second_thread.start()
四、进程和线程对比
- 进程和线程都是完成多任务的一种方式
- 多进程要比多线程消耗的资源多,但是多进程开发比单进程多线程开发稳定性要强,某个进程挂掉不会影响其它进程。
- 多进程可以使用cpu的多核运行,多线程可以共享全局变量。
- 线程不能单独执行必须依附在进程里面
<end>