多线程
一个进程中有多个线程就是多线程。
一个进程中至少有一个线程,并作为程序的入口,这个就是主线程。一个进程至少有一个主进程,其他线程称为工作线程。
线程安全:线程执行一段代码,不会产生不确定的结果,那这段代码就是线程安全。(例如print()线程不安全)
线程的daemon属性
daemon属性:表示线程是否是daemon线程,这个值必须在start()之前设置,否则引发RuntimeError异常
isDaemon():是否是daemon线程
setDaemon():设置为daemon线程,必须在start方法之前设置
线程具有一个daemon属性,可以设置为Ture或False,也可以不设置,默认值为None.如果不设置daemon就取当前的daemon来设置它,主线程是Non-daemon。工作线程不设置daemon属性,则默认是daemon = False .python程序在没有活着的non-daemon线程运行时退出。
join()方法
join(timeout)是线程的标准方法之一。
一个线程中调用里那个一个线程的join方法,调用者将被阻塞,知道盗用线程终止。一个线程可以被join多次。
daemon线程的应用场景
1:后台任务,如发送心跳包、监控,这种场景最多
2:主线程工作才有用的线程,如主线程中维护的公共资源,主线程已经清理了,准备退出,而工作线程使用这些资源工作也没有意义了,一起退出最合适。
3:随时可以被终止的线程
threading.local类
运行时,threading.local实例处在不同的线程中,就从大字典中找到当前线程相关键值对中的字典,覆盖threading.local实例的__dict__。这样就可以在不同的线程中,安全德使用线程独有的数据做到线程间数据隔离,如同本地变量一样安全。
定时器Timer/延迟执行
threading.Timer(interval,function,args=None,Kwargs=None)
start方法执行之后,Timer对象会处于等待状态,等待了interval秒之后,开始执行function函数的。Timer提供了cancel方法,用来取消一个未执行的函数。
Event
是线程间通信机制中最简单的实现,使用一个内部的标记flag,通过flag的True或False的表换来进行操作。
set():标记设置为Ture
clear():标记设置为False
is_set():标记是否为Ture
wait(timeou):设置等待标记为Ture的时长,None为无限等待,等到返回Ture,未等到超时了返回False
Event的wait优于time.sleep,他会更快的切换到其它线程,提高并发效率。
lock
锁,凡是存在共享资源争抢的地方都可以使用锁,从而保证只有一个使用者可以完全使用这个资源。一旦线程获得锁,其他试图获取锁的线程将被阻塞。
acquire(blocking=True,timeout=-1):默认阻塞,阻塞可以设置超时时间,非阻塞时,timeout禁止设置。成功获取锁,返回True,否则返回Flase
release():释放锁,可以从任何线程调用释放。已上锁的多,会被重置未unlocked。未上锁的调用,会派出RuntimeError异常。
加锁、解锁
一般来说,加锁就需要解锁,但加锁后解锁前,还有一些代码执行,就有可能抛出异常,一旦出现异常,锁无法释放,但是当前线程可能因为这个异常被终止了,这就产生了死锁。
加锁、解锁常用的语句:
1:使用try ... funally语句保证锁的释放
2:with上下文管理,锁随想支持上下位管理。
锁的应用:
锁适合用于访问和修改同一个共享资源的时候,即读写同一个资源的时候。
注意事项:
1:少用锁,必要时使用锁,使用了锁,多线程访问被锁的资源时,就成了串行,要么排队执行,要么争抢执行。
2:加锁时间越短越好,不需要就立即释放。
3:一定要避免死锁。
Rlock可重入锁
可重入锁,是线程相关的锁。可在一个线程中获取锁,并可继续在同一个线程中不阻塞获取锁,当锁为释放完,其他线程获取锁就会阻塞。知道当前持有锁的线程释放完锁。
Conditon
构造方法Consition(lock=None),可以传入一个Lock或者Rlock对象,默认是Rlock
acquire(*args):获取锁
wait(self.timeout=None):等待或超时
notify(n =1):唤醒至多指定数目个数的等待的线程,没有线程等待的线程就没有任何操作
notify_all():唤醒所有等待的线程
condition用于生产者,消费者模型,为了解决生产者消费者速度匹配的问题。由于condition内部使用了锁,最好的方式是使用with上下文。
Barrier
Barrier(parties,action=None,timeout=None):构建Barrier对象,指定参与方数目。timeout是wait方法未指定超时的默认值。
n_waiting:当前在barrier中等待的线程数
parties:资源的个数。
broken:如果broken处于打破的状态,放回True
abort():将将barrier置于broken状态,等待中的线程或者调用等待方法的线程中都会抛出BrokenBarrierError异常,知道reset方法来恢复barrier
reset():恢复barrier,重新开始拦截。
wait方法超时发生,barrier将处于broken状态,知道reset()
semaphore信号量
Semaphore(value=1):构造方法,value小于0,抛ValueError异常
acquite(blocking=True,timeout=None):获取信号量,计数器减1,获取成功返回True
release():释放信号量,计数器加1
semaphore问题
如果遇到release释放次数大于初始值,计数器会增加,超过我们的最大值。
解决方法:
使用Boundedsemaphore类,有界信号量,不允许使用release超出初始值的范围,否则派出ValueError异常。
锁和信号量
锁,只允许同一个时间一个线程独占资源,它是特殊的信号量,即信号量计数器初始值为1.
信号量,可以多个线程访问共享资源,但这个共享资源数量有限。
锁,可以看做特殊的型号量。