线程相关理论
1.进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。
2.多线程(即多个控制线程)的概念是,在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间,相当于一个车间内有多条流水线,都共用一个车间的资源。(一个进程里面开多个线程(共享同一个进程里面的内存空间))
注意:
1.所有进程里面真正干活的是线程(进程里面有线程)
2.进程只是用来把资源互相隔离开,而线程才是真正负责cpu来调动它的
线程创建的开销小
创建一个进程,就是创建一个车间(申请空间,在该空间内建至少一条流水线)
而建线程,就只是在一个车间内造一条流水线,无需申请空间,所以创建开销小
线程和进程的区别
1.创建线程比进程开销小(开一个进程,里面就有空间了,而线程在进程里面,就没必要在开一个空间了)
2.多线程一定是在一个进程里面开启的,共享进程里面的资源
3.线程启动的速度快
4.同一进程下的多个线程共享进程的资源,而多个进程之间内存空间是隔离的
在wins下开进程,子进程不会拷贝父进程的
在linux下开进程,子进程会完全拷贝父进程的
5.线程可以跟它所在的进程之内 的线程通信
为何要使用多线程
多线程指的是,在一个进程中开启多个线程,简单的讲:如果多个任务共用一块地址空间,那么必须在一个进程内开启多个线程。详细的讲分为4点:
1. 多线程共享一个进程的地址空间
2. 线程比进程更轻量级,线程比进程更容易创建可撤销,在许多操作系统中,创建一个线程比创建一个进程要快10-100倍,在有大量线程需要动态和快速修改时,这一特性很有用
3. 若多个线程都是cpu密集型的,那么并不能获得性能上的增强,但是如果存在大量的计算和大量的I/O处理,拥有多个线程允许这些活动彼此重叠运行,从而会加快程序执行的速度。
4. 在多cpu系统中,为了最大限度的利用多核,可以开启多个线程,比开进程开销要小的多。(这一条并不适用于python)
死锁,递归锁,信号量,Event事件,线程Queue
一、死锁现象和递归锁
进程也是有死锁的
所谓死锁:是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种相互等待的现象,若无外力作用。
它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
那么怎么解决死锁现象?
解决方法,递归锁:在python中为了支持在同一线程中多次请求同一资源,python提供可重入锁RLOCK()。
这个RLock内部维护着一个Lock和一个counter变量,counter记录着acquire的次数,从而使得资源可以被多次require
直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用Rlock代替Lock,则不会发生死锁
注:一个线程拿到锁,counter加1,该线程内又碰到加锁的情况,则counter继续加1,这期间所有其他进程都只能等待,等待该线程释放所有锁,则counter递减到0为止。
二、信号量Semaphore(其实也是一把锁)
Semaphore管理内置的一个计数器
Semaphore与进程池看起来类似,但是是完全不同的概念。
进程池:Pool(4),最大只能产生4个进程,而且从头到尾都只是这4个进程,不会产生新的。
信号量:信号量是产生的一堆进程/线程,即产生了多个任务都去抢那一把锁
三、Event(同步条件对象)
线程的一个关键特性是每个线程都独立运行且状态不可预测。如果程序中的其他线程需要通过判断某个线程的状态来确定自己下一步的操作,这时线程同步问题就会变得非常棘手。为了解决这些问题,我们需要使用threading库中的Event对象。对象包含一个可由线程设置的信号标志,它允许线程等待某些事件的发生。在初始情况下,Event对象中的信号标志被设置为假。如果有线程等待一个Event对象, 而这个Event对象的标志为假,那么这个线程将会被一直阻塞直至该标志为真。一个线程如果将一个Event对象的信号标志设置为真,它将唤醒所有等待这个Event对象的线程。如果一个线程等待一个已经被设置为真的Event对象,那么它将忽略这个事件, 继续执行。
from threading import Event
Event.isSet() #返回event的状态值
Event.wait() #如果 event.isSet()==False将阻塞线程;
Event.set() #设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
Event.clear() #恢复
围绕一个标志位在做操作
四、线程队列
queue队列:使用import queue,用法与进程Queue一样
- queue.Queue(maxsize=0) #先进先出
- queue.LifoQueue(maxsize=0)#先进后出
- queue.PriorityQueue(maxsize=0) #存储数据时可设置优先级的队列
五、多线程性能测试
1、多核也就是多个cpu
(1)、cpu越多,提高的是计算的能力
(2)、如果程序是IO操作的时候(多核和单核一样),再多的cpu也没有意义
2、实现并发
第一种:一个进程下,开多个线程
第二种:开多个进程
3、多进程
优点:可以利用多核
缺点:开销大
4、多线程
优点:开销小
缺点:不可以利用多核
5、多进程和多线程的应用场景
1.计算密集型:也就是计算多,IO少
如果是计算密集型,就用多进程(如金融分析等)
2.IO密集型:也就是IO多,计算少
如果是IO密集型的,就用多线程(一般遇到的都是IO密集型的)