一、多任务的介绍
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() # 总结: 主进程会等待所有的子进程执行完成以后程序再退出 3.
三、线程
线程是进程中执行代码的一个分支,每个执行分支(线程)要想工作执行代码需要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>