1. 定义
CPU调度的基本单位
一个进程包含多个线程,至少一个主线程,再由主线程创建多个子线程
2. 多线程
- 导入线程模块
import threading
- 创建线程
线程对象名 = threading.Thread(target=线程名)
Thread([group [, target [, name [, args [, kwargs]]]]])
- group: 线程组,目前只能使用None
- target: 执行的目标任务名
- args: 以元组的方式给执行任务传参
- kwargs: 以字典方式给执行任务传参
- name: 线程名,一般不用设置
- 启动线程
线程对象名.start()
3. 带有参数的线程
- args= ()
- kwargs= {}
- 代码示例
import threading
def show_info(age):
print(age)
if __name__ == '__main__':
# 方式一:元祖
show_info_process = threading.Thread(target=show_info, args=(10,))
# 方式二:字典
show_info_process1 = threading.Thread(target=show_info, kwargs={'age':10})
show_info_process.start()
show_info_process1.start()
4. 注意点
- 不同线程间执行无序
- 主线程会等所有子线程结束后结束
- 设子线程为守护主线程,
Thread(.., daemon = True)
- 设子线程为守护主线程,
- 线程间共享全局变量
- 共享全局变量可能会出问题
- 线程同步:不同线程间顺序执行,通过
线程对象名.join()
结束完当前线程才开始下一个 - 通过互斥锁,对共享的变量上锁,保证同一时刻只有一个线程使用,多个线程共享时,要对所有会改变共享变量的线程上锁和解锁
- 设置锁
lock = threading.Lock()
- 共享变量使用前上锁
lock.acquire()
- 用完后一定要解锁
lock.release()
- 设置锁
- 线程同步:不同线程间顺序执行,通过
- 代码示例
import threading
# 全局变量
g_num = 0
# 1. 设置锁
lock = threading.Lock()
def task1():
# 2. 上锁
lock.acquire()
global g_num
for i in range(1000000):
g_num += 1
# 3. 解锁
lock.release()
print(g_num)
def task2():
# 2. 上锁
lock.acquire()
global g_num
for i in range(1000000):
g_num += 1
# 3. 解锁
lock.release()
print(g_num)
if __name__ == '__main__':
task1_process = threading.Thread(target=task1)
task2_process = threading.Thread(target=task2)
task1_process.start()
# 1. 当前线程执行完后才能去执行第二个
# task1_process.join()
task2_process.start()
注意死锁
- 在上锁后,一直没有释放锁;
- 各种资源分配不合理导致资源竞争死锁
5. 进程和线程对比
- 相关
- 先有进程后有线程
- 一个进程至少一个主线程
- 区别
进程 | 线程 |
---|---|
创建时资源消耗大 | 小 |
资源分配基本单位 | cpu调度基本单位 |
多进程更稳定 | 单进程多线程不稳定 |
全局变量不共享 | 共享,但要注意互斥、死锁 |
能独立存在 | 必须要先有进程 |
- 优缺点
- 进程
- 优点:可以使用多核,适合大量计算型,数据处理
- 缺点:资源消耗大
- 线程
- 优点:可以多任务,消耗小,适合非计算型开发、I/O操作、文件操作
- 缺点:只能单核
- 进程