使用多线程编程和一个共享的数据结构如 Queue(一种多线程队列数据结构,先进先出/先进后出)
1.1、多线程的构成方式:
1.1.1、UserRequestThread: 负责读取客户的输入, 可能是一个 I/O 信道。程序可能创建多个线程,每个客户一个,请求会被放入队列中。
1.1.2、RequestProcessor: 一个负责从队列中获取并处理请求的线程, 它为下面那种线程提供输出。
1.1.3、ReplyThread: 负责把给用户的输出取出来,如果是网络应用程序就把结果发送出去,否则就保存到本地文件系统或数据库中。
Python、线程和全局解释器锁
1.2、全局解释器锁(GIL)
Python 代码的执行由 Python 虚拟机(也叫解释器主循环)来控制。Python 在设计之初就考虑到要在主循环中,同时只有一个线程在执行,也就是伪多线程。
1.2.1、对 Python 虚拟机的访问由全局解释器锁(GIL)来控制,在多线程环境中,Python 虚拟机按以下方式执行:
python虚拟机运行方式1.2.2、Python 提供了几个用于多线程编程的模块,包括 thread, threading 和 Queue 等。thread 和threading 模块允许程序员创建和管理线程。thread 模块提供了基本的线程和锁的支持,而 threading提供了更高级别,功能更强的线程管理的功能。Queue 模块允许用户创建一个可以用于多个线程之间共享数据的队列数据结构
threading 模块对象threading 模块
1.3.、守护线程
1.3.1、threading 模块支持守护线程, 它们是这样工作的: 守护线程一般是一个等待客户请求的服务器,如果没有客户提出请求,它就在那等着。如果你设定一个线程为守护线程,就表示你在说这个线程是不重要的,在进程退出的时候,不用等待这个线程退出。
1.3.2、设置守护线程的方法:
在线程开始(调用 thread.start())之前, 调用 setDaemon()函数设定线程的 daemon 标志(thread.setDaemon(True)) 就表示这个线程“不重要”
1.3.3、对于非守护线程,可以显式地调用thread.setDaemon(False)以保证其 daemon 标志为 False。 也可以调用 thread.isDaemon()函数来判断其 daemon 标志的值。新的子线程会继承其父线程的 daemon 标志。
1.3.4、整个 Python 会在所有的非守护线程退出后才会结束,即进程中没有非守护线程存在的时候才结束。
1.4、threading.Thread类
创建一个 Thread 的实例,传给它一个函数 创建一个 Thread 的实例,传给它一个可调用的类对象1.4.1、threading 模块中的其它函数
threading 模块中的其它函数1.5、生产者-消费者问题和 Queue 模块
Queue 模块 队列的读写操作1 队列操作2 线程生命周期1.5.1、线程同步(锁)
多线程的优势在于可以同时运行多个任务,至少感觉起来是这样,但是当线程需要共享数据时,可能存在数据不同步的问题。
1.5.2、#构造方法:
Thread(group=None,target=None,name=None,args=(),kwargs={})
group:线程组,目前还没有实现,库引用时提示必须是None
target:要执行的方法
name:线程名
args/kwargs:要传入方法的参数,args和kwargs两个参数其实是二选一
Lock():lock是可用的最低级的同步指令,Lock处于锁定状态时,不被特定的线程拥有,Lock包含2种状态--锁定和非锁定以及2个基本的方法
1.5.3、#实例方法
isAlive():返回线程是否在运行
get/setName(name):获取/设置线程名
is/setDaemon(bool):获取/设置是否守护线程。初始值从创建该线程的线程继承,当没有非守护线程仍在运行时,程序将终止
start():启动线程
join([timeout]):阻塞当前上下文环境的线程。
acquire([timeout]):使线程进入同步阻塞状态,尝试获得锁定
release():释放锁,使用前线程必须已获得锁定,否则将抛出异常
网友评论