Python中多线程总结

2023-01-31 02:01:01 python 多线程

Python中的多线程


多线程


一个进程中有多个线程就是多线程

一个进程中至少有一个线程,并作为程序的入口,这个就是主线程。一个进程至少有一个主进程,其他线程称为工作线程。


线程安全:线程执行一段代码,不会产生不确定的结果,那这段代码就是线程安全。(例如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.

信号量,可以多个线程访问共享资源,但这个共享资源数量有限。

锁,可以看做特殊的型号量。


相关文章