参考自:
多任务可以由多进程完成,也可以由一个进程内的多线程完成
Python多线程
- 一个进程默认会启动一个线程,我们称作为主线程。主线程又可以启动多个新的线程
- threading模块有一个current_thread()方法表示返回当前线程实例
- 主线程实例名字叫MainThread
- 子线程在创建时指定,这里定义为LoopThread
- start()方法启动线程
- join()方法等待线程结束
|
|
执行结果:
|
|
Lock
在多线程中,所有变量是由所有线程共享的,因此任何变量都会被任何线程修改,所以线程之间数据共享最大的危险就是多个线程去修改一个变量,会把内容给改乱了
下面代码就没有加上锁,balance为0,开启两个线程,理论上运行结果应该都是0,但由于线程的调度是由操作系统决定的,只要循环次数够多就不会一直为0
看下上Lock后的代码
这里给change_it()上了锁,当一个线程执行chang_it()的时候,其他线程就不能同时执行change_it(),需要等到这个线程执行完毕,并且释放锁,其他线程可以执行change_it()。锁只有一个,无论有多少个线程,同一时刻只有一个线程会有这个锁,其他线程处于等待状态,这样修改就不会发生冲突
- 锁的好处:确保一段代码只有一个线程从头到尾执行完毕,不会发生冲突
- 锁的坏处:无法实现多线程的并发执行,包含锁的代码只能以单线程运行,效率会大打折扣
- 由于可以存在多个锁,不同的线程持有不同的锁,在试图获取对方锁时,可能会造成死锁,造成多个线程全部挂起,不能执行也无法结束,只能强制关闭
|
|
GIL(Global Interperter Lock)全局解释锁
Python的多线程代码并不能利用多核的优势,而是通过GIL来处理。对于计算型任务(CPU计算占主要的任务),使用多线程GIL就会使运行速度变慢,这里举个例子看下Gil的问题。执行结果,开启多线程后反而速度更慢
Python为了保证线程安全而采取的独立线程运行的限制,就是一个核在同一时间只能运行一个线程;对于IO密集型的任务,Python多线程就能起到作用,提高并发效率
|
|
执行结果:
|
|
Semaphore(信号量)
前面Lock小结里面就讲过所有变量都是由所有线程共享的,要防止多个线程同时改修一个变量,需要控制同时访问的数量。信号量的同步基于内部的计数器,每调用一次acquire()就减1,每调用一次release()就+1,acquire就被阻塞了
|
|
执行结果:
这里我们限制了同时访问资源的数量为3
|
|
Queue
多线程的队列,这里以生产者/消费者的模式来做例子,生产者把生产出来的消息放入队列,消费者从这个队列中去执行对应的消息
首先这个进程创建队列,然后传递给两个线程
|
|