Python学习笔记18:Python多线程编程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tiana0/article/details/52015509

1、引言/动机
多线程(MT)并行运行相互独立的子任务,提升整个任务的效率。
多线程适合的任务的特点:它们本质上是异步的,需要有多个并发事务,各个事务的运行顺序可以是不确定的,随机的,不可预测的。运算密集型的任务一般较容易分隔成多个子任务。

2、进程和线程
进程有自己的地址空间、内存、数据栈及其他记录运行轨迹的辅助数据。
进程之间使用进程间通讯(IPC)共享信息。OS为进程公平分配时间,进程也可以通过fork和spawn操作完成其他任务。
线程(轻量级进程)所有线程运行在同一个进程中,共享相同的运行环境。线程有自己的指令指针,记录自己运行到什么地方。线程的运行可能被抢占(中断)、暂时挂起(睡眠)。一个进程中各线程间共享一片数据空间,线程之间可以方便共享数据及相互通讯。
竞态条件指多个线程共同访问同一片数据,由于数据访问的顺序不一致有可能导致数据结果的不一致的问题。线程库通过同步原语来控制线程的执行和数据的访问。

3、Python、线程和全局解释器锁
(1)全局解释器锁
Python虚拟机(也叫解释器主循环)控制Python代码执行。在主循环中,同时只有一个线程在执行。对Python虚拟机的访问由全局解释器锁(global interpreter lock,GIL)来控制。
在多线程环境中,Python虚拟机按照以下方式执行。
①设置GIL。
②切换到一个线程去执行。
③运行:a.指定数量的字节码的指令,或者b.线程主动让出控制(可以调用time.sleep(0))
④把线程设置为睡眠状态。
⑤解锁GIL。
⑥再次重复以上所有步骤。
在调用外部代码(如C/C++扩展函数)时,GIL将会被锁定,直到函数结束为止。
(2)退出线程
调用thread.exit()或sys.exit()或抛出一个SystemExit异常等。不过,不可以直接”杀掉“一个线程。

  • thread模块:不建议使用,当线程退出时,所有其它线程没有被清除就退出了。
  • threading模块:可确保所有”重要的“子线程都退出后,进程才会结束。

(3)在Python中使用线程
Python提供了几个用于多线程编程的模块,包括thread、threading和Queue等。
thread和threading用于创建和管理线程。
thread模块提供了基本的线程和锁的支持,而threading模块提供更高级别,功能更强的线程管理功能。threading模块的同步原语更丰富。
不建议使用thread模块:thread功能没有threading完善;thread对线程结束工作没有进行适当的控制。

4、thread模块
thread模块除了产生线程外,也提供了基本的同步数据结构锁对象(lock object,也叫原语锁、简单锁、互斥锁、互斥量、二值信号量)。
(1)模块函数

  • start_new_thread(function,args,kwargs=None)产生一个新线程来运行函数function,该函数前两个参数是必须的,就算运行的函数不需要参数,也要传入一个空元组。
  • allocate_lock() 分配一个LockType类型的锁对象
  • exit() 让线程退出

(2)LockType类型锁对象方法

  • acquire(wait=None)尝试获取锁对象
  • locked() 如果获取了锁对象返回True,否则返回False
  • release() 释放锁

5、threading模块
threading模块提供了Thread类,还提供了各种很好用的同步机制。
(1)threading模块对象

  • Thread 表示一个线程的执行的对象
  • Lock 锁原语对象
  • Rlock 可重入锁对象,使单线程可以再次获得已经获得了的锁(递归锁定)
  • Condition 条件变量对象,能让线程停下来等待其他线程满足了某个”条件”。
  • Event 通用的条件变量。多个线程可以等待某个事件的发生,当事件发生后,所有的线程都会被激活
  • Semaphore 为等待锁的线程提供一个类似“等待室”的结构
  • BoundedSemaphore 与Semaphore类似,只是它不允许超过初始值
  • Timer 与Thread类似,只是它要等待一段时间后才开始执行

(2)Thread类
Thread类可以用多种方法来创建线程。

  • 创建一个Thread类的实例,传给它一个函数。
  • 创建一个Thread类的实例,传给它一个可调用的类对象。
  • 从Thread类派生出一个子类,创建一个这个子类的实例。

Thread类有很多thread模块里没有的函数。

  • start() 开始线程的执行
  • run() 定义线程的功能的函数(一般会被子类重写)
  • join(timeout=None) 程序挂起,直到线程结束;如果给出timeout,则最多阻塞timeout秒
  • getName() 返回线程的名字
  • setName(name) 设置线程的名字
  • isAlive() 表示线程是否还在运行中
  • isDaemon() 返回线程的daemon标志
  • setDaemon(daemonic) 把线程的daemon标志设置为daemonic(一定要在调用start()函数前调用)

(3)threading模块中的其他函数

  • activeCount() 当前活动的线程对象的数量
  • currentThread() 返回当前线程对象
  • enumerate() 返回当前活动线程的列表
  • settrace(func) 为所有线程设置一个跟踪函数
  • setprofile(func) 为所有线程设置一个profile函数

(4)补充
守护线程:若设置一个线程为守护线程,在进程退出时,不用等待这个线程退出。整个Python会在所有的非守护线程退出后才结束。threading模块支持守护线程,thread模块不支持。

  • 使用setDaemon()函数设定线程的daemon标志来设置守护线程。thread.setDaemon(True)就表示这个线程”不重要“
  • thread.isDaemon()函数来判断其daemon标志的值。新的子线程会继承其父线程的daemon标志。

6、Queue模块
Queue模块可以用来进行线程间的通讯,让各个线程之间共享数据。
(1)Queue模块函数

  • queue(size) 创建一个大小为size的Queue对象

(2)Queue对象函数

  • qsize() 返回队列的大小(由于在返回的时候,队列可能会被其它线程修改,所以这个值是近似值)
  • empty() 返回队列是否为空
  • full() 返回队列是否已满
  • put(item,block=0) 把item放到队列中,如果给了block,函数会一直阻塞到队列中有空间位置
  • get(block=0) 从队列中取一个对象,如果给了block,函数会一直阻塞到队列中有对象为止

7 、相关模块

  • thread 基本的、低级别的线程模块
  • threading 高级别的线程和同步对象
  • Queue 供多线程使用的同步先进先出队列
  • mutex 互斥对象
  • SocketServer 具有线程控制的TCP和UDP管理器
阅读更多
换一批

没有更多推荐了,返回首页