Python进阶学习笔记之——多线程编程

多线程编程

1、Python 的多线程支持模块简介

Python 提供了多个模块来支持多线程编程,包括 thread、threading 和 Queue 模块等。程序是可以使用 thread 和 threading 模块来创建与管理线程。thread 模块提供了基本的线程和锁定支持而 threading 模块提供了更高级别、功能更全面的线程管理使用 Queue 模块,用户可以创建一支队列数据结构,用于在多线程之间进行共享

  • 核心提示:避免使用 thread 模块

    推荐使用更高级别的 threading 模块,而不使用 thread 模块有很多原因:

    1. threading 模块更加先进,有更好的线程支持,并且 thread 模块中的一些属性会和 threading 模块有冲突。
    2. 另一个原因是低级别的 thread 模块拥有的同步原语很少(实际只有一个),而 threading 模块则很多。
    3. 避免使用 thread 模块的另一个原因是它对于进程如何退出没有控制。当主线程结束时,所有其他线程也都强制结束,不会发出警告或者进行适当的清理。但至少 threading 模块能确保重要的子线程在进程退出前结束。

2、thread 模块

除了派生线程外,thread 模块还提供了基本的同步数据结构,称为锁对象(也称为原语锁、简单锁、互斥锁、互斥和二进制信号量)。下表展示了一些常用的线程函数以及 LockType 锁对象的方法:

函数/方法 说明
thread 模块的函数
start_new_thread(function,args,kwargs=None) 派生一个新的线程,使用给定的 args 和可选的 kwargs 来执行 function
allocate_lock() 分配 LockType 锁对象
exit() 给线程退出指令
LockType 锁对象的方法
acquire(wait=None) 尝试获取锁对象
locked() 如果获取了锁对象则返回 True,否则,返回 False
release() 释放锁

3、threading 模块

除了 Thread 类之外,该模块还包括许多非常好用的同步机制。下表给出了 threading 模块中所有可用对象的列表。

对象 说明
Thread 表示一个执行线程的对象
Lock 锁原语对象
RLock 可重入锁对象,使单一线程可以(再次)获得已持有的锁(递归锁)
Condition 条件变量对象,使得一个线程等待另一个线程满足特定的 “条件”,比如改变状态或某个数据值
Event 条件变量的通用版本,任意数量的线程等待某个事件的发生,在该事件发生后所有线程将被激活
Semaphore 为线程间共享的有限资源提供一个 “计数器”,如果没有可用资源时会阻塞
BoundedSemaphore 与 Semaphore 相似,不过它不允许超过初始值
Timer 与 Thread 相似,不过它要在运行前等待一段时间
Barrier 创建一个 “障碍”,必须达到指定数量的线程后才可以继续
  • 核心提示:守护线程

    避免使用 thread 的另一个原因是该模块不支持守护线程的概念。**当主线程退出时,所有子线程都将终止,不管他们是否正在工作。**如果你不想发生这种行为,就要引入守护线程了。

    threading 模块支持守护线程,其工作方式是:守护线程一般是一个等待客户端请求的服务器如果没有客户端请求,守护线程就是空闲的。如果把一个线程设置成守护线程,就表示这个线程是不重要的,进程退出时不需要等待这个线程执行完成

    要将一个线程设置成守护线程,需要在启动线程之前执行如下语句:thread.daemon = True。同样,要检查线程的守护状态,也只需要检查这个值即可。一个新的线程会继承父线程的守护标记。整个 Python 程序将在所有非守护线程退出后才退出

3.1、Thread 类

threading 模块的 Thread 类是主要的执行对象。

属性 说明
Thread 对象数据属性
name 线程名
ident 线程的标识符
daemon 布尔标识,标识这个线程是否是守护线程
Thread 对象方法
_init_(group=None,target(func)=None,name=None,args=(),kwargs={},verbose=None,daemon=None) 实例化一个线程对象,需要有一个可调用的 target,以及其参数 args 或 kwargs。还可以传递 name 或 group 参数,不过后者还未实现。此外,verbose 标志也是可以接受的。而 daemon 的值也将会设定 thread.daemon 属性/标志
start() 开始执行该进程
run() 定义线程功能的方法(通常在子类中被应用开发者重写)
join(timeout=None) 直至启动的线程终止之前一直挂起;除非给出了 timeout,否则会一直阻塞
getName() 返回线程名(更好的方法是设置(或获取)thread.name 属性,或者在实例化过程中传递该属性)
setName() 设定线程名(同上)
isAlivel/is_alive() 布尔标识,表示这个线程是否还存活
isDaemon() 如果是守护线程,则返回 True;否则,返回 False(更好的方法是设置(或获取)thread.daemon 属性,或者在实例化过程中传递该属性)
setDaemon(daemon) 把线程的守护标识设定为布尔值 daemonic(必须在线程 start() 之前调用)(同上)

使用 Thread 类,可以有很多种方法创建线程:

  • 创建 Thread 的实例,传给它一个函数;
  • 创建 Thread 的实际,传给它一个可调用的类实例;
  • 派生 Thread 的子类,并创建子类的实例。
3.1.1、派生 Thread 的子类,并创建子类的实例
import threading
from time import sleep,ctime

loops = (4,2)

class MyThread(threading.Thread):
    def __init__(self,func,args,name=''):
        threading.Thread.__init__(self)
        self.name = name
        self.func = func
        self.args = args

    def run(self):
        self.func(*self.args)

def loop(nloop,nsec):
    print('start loop',nloop,'at:',ctime())
    sleep(nsec)
    print('loop',nloop,'done at:',ctime())

print('starting at:',ctime())
threads = []
nloops = range(len(loops))

for i in nloops:
    t = MyThread(loop,(i,loops[i]),loop.__name__)
    threads.append(t)

for i in nloops:
    threads[i].start()

for i in nloops:
    threads[i].join()

print('all DONE at:',ctime())
starting at: Thu Aug 20 16:09:44 2020
start loop 0 at: Thu Aug 20 16:09:44 2020
start loop 
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值