Python - 多任务
一、多任务开发
1、概念:同一时间内执行多个任务
2、优点:充分利用CPU资源,提高程序的执行效率
3、执行方式
- 并发:在一段时间内交替执行任务
- 并行:始终有多个软件一起执行(多核 CPU)
4、实现方式
多进程开发 | 多线程开发 |
---|---|
可以用多核 | 不能使用多核 |
资源开销大 | 资源开销小 |
稳定性强 | 稳定性弱 |
进程和线程的关系:
- 进程:操作系统进行资源分配的基本单位
- 线程:CPU 资源调度的最小单位
程序运行至少有一个进程,一个进程默认有一个线程,进程里可以创建多个线程,线程依附进程
二、多进程开发
1. 创建子进程实例对象
- 创建子进程实例对象:
multiprocessing.Process(target=执行任务名)
- 创建实例对象常用参数
参数 | 说明 |
---|---|
group | 指定进程组,默认为None,且目前不支持修改 |
target | 执行任务名 |
name | 进程名 |
args | 以元组方式给执行任务传参,需要和执行任务形参的顺序保持一致 |
kwargs | 以字典方式给执行任务传参,key值需要和形参名保持一致 |
获取当前进程名:multiprocessing.current_process()
2. 子进程对象常用方法和属性
- 常用方法
方法 | 说明 |
---|---|
start() | 启动子进程实例(创建子进程) |
join() | 等待子进程执行结束,再继续向下执行 |
terminate() | 不管任务是否完成,立即终止子进程 |
- 常用属性
属性 | 说明 |
---|---|
name | 当前进程名称,默认为Process-N,N为从1开始递增的整数 |
daemon | 是否守护主进程,默认为 False |
3. 获取进程编号方法
- 获取当前进程编号:
os.getpid()
- 获取当前父进程编号:
os.getppid()
强制杀死子进程:os.kill(进程编号,9)
4. 多进程开发注意点
进程之间的执行是无序的
进程之间不共享全局变量:创建子进程会对主进程资源进行拷贝,也就是主进程的一个副本
主进程会等待所有的子进程执行结束后再结束,若需要子进程跟随主进程结束,有两种方式:
- 守护主进程:
子进程对象.daemon = True
- 销毁子进程:
子进程对象.terminate()
- 守护主进程:
5. 代码示例
1 | import multiprocessing |
- 运行结果
三、多线程开发
1. 创建子线程实例对象
- 创建子线程实例对象:
threading.Thread(target=执行任务名)
- 创建实例对象常用参数
参数 | 说明 |
---|---|
group | 指定线程组,默认为None,且目前不支持修改 |
target | 执行任务名 |
name | 线程名 |
args | 以元组方式给执行任务传参,需要和执行任务形参的顺序保持一致 |
kwargs | 以字典方式给执行任务传参,key值需要和形参名保持一致 |
daemon | 是否守护主线程,默认为 False |
获取当前进程名:threading.current_thread()
2. 子线程对象常用方法和属性
- 常用方法
方法 | 说明 |
---|---|
start() | 启动子线程实例(创建子线程) |
join() | 等待子线程执行结束,再继续向下执行 |
- 常用属性
属性 | 说明 |
---|---|
name | 当前进程名称,默认为Thread-N,N为从1开始递增的整数 |
3. 互斥锁
作用:保证同一时刻只能有一个线程去操作共享数据,保证共享数据不会出现错误问题
缺点:会影响代码的执行效率,多任务改成了单任务执行;如果没有使用好容易出现死锁的情况
- 创建锁对象:
threading.Lock()
- 上锁:
锁对象.acquire()
- 释放锁:
锁对象.release()
4. 多线程开发注意点
线程之间执行是无序的
线程之间共享全局变量,但容易出现数据错误问题,需要线程同步:
- 方式一:设置线程等待:
子线程对象.join()
- 方式二:互斥锁:对共享数据进行锁定,保证同一时刻只能有一个线程去操作
- 方式一:设置线程等待:
主线程会等待所有的子线程执行结束后再结束,若需要子线程跟随主线程结束,可以设置守护主进程:创建子线程示例对象时,设置 daemon 属性为 True
5. 代码示例
1 | import threading |
- 运行结果
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 妙妙屋!