Python线程

51 阅读3分钟

线程

线程被称为轻量级进程,是CPU执行的最小单位

一般线程由一个父进程诞生,可以认为是在一个主进程中并行运行的一些**'迷你进程'**

  • 线程的属性

一个进程中的各个线程和主进程共享同一片数据空间

相比进程而言,线程间的通信及数据共享更加容易

线程一般以并发方式进行,而且线程之间共享数据,所以可能会导致在多核心CPU下,一个数据被多个线程同时使用,使数据混淆所以还会有各种各样的同步原语来解决这样的问题,保证数据资源的稳定

主进程死亡,其中全部子线程都会死亡

线程也有自己的身份标识,但是只在当前的进程上下文中有意义,这个标示常称为TID


GIL

Python代码的执行是由Python虚拟机进行控制;进行分配内存,系统管理等等

在设计之初,这些大佬们考虑,同一时间只能由一个线程在执行;类似单核CPU系统中的多进程一样,同时只能有一个进程被CPU处理

这就引出了一个叫做GIL全局解释器锁的东西;多线程执环境下,一个线程在执行前,解释器首先会为这个线程设置GIL锁,只有被加锁的线程才会被CPU执行处理,但是这也就导致,在多核处理器下,其他线程只能是看着这个持有唯一锁的线程工作;线程工作结束,释放锁

GIL锁的存在,导致python的多线程不是实际的并发行为,只是简单的io切换cpu时间片切换;不过好消息是,关于线程全局解释性锁GIL的问题,已经在各个版本逐步完善ceval.c

线程模块

Python3中,支持线程的有两个模块:_threadthreading

_thread提供了基本的线程创建和锁支持

threading提供了更全面,更高级的线程管理、所以都推荐使用threading模块

虽然Python中的线程有GIL锁,但是在进行IO密集型工作时,IO等待时候,GIL锁会被释放,其他线程继续持锁工作,此外线程在进行cpu上下文切换时所需的损耗要远小于进程工作切换

  • 注意:cpu密集选择多进程,io密集选择多线程

threading

import threading
t = Thread(target=None, name=None, args=(), kwargs=None)
'''
target: 线程任务函数
name: 线程名
args: 线程任务函数的参数,以位置参数形式传递
kwargs: 线程任务函数的操作,以命名参数形式传递
'''
t.name # 线程名
t.start() # 开启线程
t.join(time=None) # 阻塞等待线程执行结束
# 参数指定时,将指定阻塞多少秒,只有在daemon值True时生效
t.daemon = True  # 设置守护线程
# 设置该属性True之后,如果没有join阻塞等待线程结束,主进程会直接退出,并且线程结束
t.getName()	# 设置线程名称
t.setName()	# 获取线程名称
t.isAlive()	t.is_alive() # 判断线程是否激活
  • 代码示例
from threading import Thread,Lock,currentThread
import time
def work():
    time.sleep(1)
    print(currentThread().name)
    return 100

def main():
    t1 = Thread(target=work)
    t1.daemon = True
    t1.start() # 启动且不回收
    print('over')

if __name__ == '__main__':
    main()