进程,线程,协程
资源分配的最小单位。是程序在处理机上的一次执行过程。进程间相互独立,内存隔离,一个进程修改数据不会影响其他进程
是CPU调度的最小单位,是进程中的一部分,一个进程内至少有一个线程,也可以开启多个线程,
线程之间资源共享.一个线程修改数据其他线程也会受影响.
是单线程下的并发.本质上是一个线程,能够在多个任务之间切换来节省一些IO时间
1.进程/线程之间的调度靠操作系统,协程是由用户程序自己控制调度的。
2.进程和线程都是同步机制,协程是异步机制。
3.协程可以保留上一次的执行状态,每次过程重入时,相当于进入上一次调用状态,协程只有在I/O密集型操作才会提高效率
4.多线程,协程用于IO密集型,如socket,爬虫,web,抢占cpu资源
5.多进程用于计算密集型,如金融分析,利用多核优势
1.线程共享内存空间,进程的内存是独立的
原因:进程资源分配的最小单位,线程没有自己的独立空间。因此对于地址空间和资源来说进程之间相互独立,各线程之间共享
2.同一个进程的线程之间可以直接交流,两个进程想通信,必须通过一个中间代理(队列和管道)来实现
3.多进程的优点是稳定性好,一个子进程崩溃了,不会影响主进程以及其余进程
缺点是创建进程的代价非常大,因为操作系统要给每个进程分配固定的资源
4.多线程优点是效率较高一些,但是致命的缺点是任何一个线程崩溃都可能,造成整个进程的崩溃,因为它们共享了进程的内存资源池
1.需要频繁创建销毁的优先使用线程;因为对进程来说创建和销毁一个进程代价是很大的
2.线程的切换速度快,切换频繁时用线程,还有耗时的操作使用线程可提高应用程序的响应
3.多机分布的用进程,多核分布用线程;
4.需要更稳定安全时,适合选择进程;需要速度时,选择线程更好
cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制),一种情况是该任务发生了阻塞,另外一种情况是该任务计算的时间过长。
对于单线程下,会不可避免程序中出现io操作:
同步IO下系统需要切换线程,让操作系统可以在IO过程中执行其他线程。但是由于大量的线程切换带来了大量的性能的浪费.
异步IO,就是当数据到达的时候触发我的回调。来减少线程切换带来性能损失。
但是这样的坏处也是很大的,每次来段数据就要判断数据够不够处理,够处理就处理吧,不够处理就在等等吧。
但是使用协程每当触发IO操作的时候就自动让出CPU给其他协程。协程的切换很轻的,协程通过这种对异步IO的封装,既保留了性能也保证了代码的容易编写和可读性。这样就保证了该线程能够最大限度地处于就绪态,即随时都可以被cpu执行的状态,
协程发生io操作时,是非阻塞的
进程三态:就绪,运行和阻塞
(1)就绪(Ready)状态
当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程状态称为就绪状态。
(2)执行/运行(Running)状态
当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状态。
(3)阻塞(Blocked)状态
正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起进程阻塞的事件可有多种,
例如,input sleep 文件的输入书输出 网络请求 recv send
1.Queue的使用:Queue是多进程安全的队列
put方法将数据插入到队列中
Get方法从队列中拿走一个数据
q.put()如果队列已经满了,程序阻塞,等待数据被别人取走,再将数据放入队列。
如果队列中的数据一直不被取走,程序就会阻塞。
q.get()如果队列中数据为为空,停在这,一直等待数据(即阻塞)
q.full() 判断队列是否满了
2.Pipe的使用
pipe用于两个进程间的通信,两个进程分别位于管道的两端,Pipe方法返回(conn1,conn2)代表一个管道的两端,
Pipe方法有dumplex参数,若该参数为True,管道为全双工模式,若为Fasle,conn1只负责接收消息,conn2只负责发送消息.
send和recv方法分别是发送和接收消息的方法, close: 关闭管道口 一般在进程中用不到的管道口就可以先关闭掉
3.信号量机制:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。
4.信号:信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生
1.锁机制:包括互斥锁 读写锁
互斥锁提供了以排他方式防止数据结构被并发修改的方法。
读写锁允许多个线程同时读共享数据,而对写操作是互斥的
2.信号量机制
3.信号
1.Value 共享数值型变量
num=multiprocessing.Value("d",10.0) # d表示数值,主进程与子进程共享这个value。(主进程与子进程都是用的同一个value)
2.Array 共享数组性
num=multiprocessing.Array("i",[1,2,3,4,5]) #主进程与子进程共享这个数组
3.Manager 共享dict list
mydict=multiprocessing.Manager().dict() #主进程与子进程共享这个字典
mylist=multiprocessing.Manager().list(range(5)) #主进程与子进程共享这个List
进程锁: 防止多个进程同时操作一套文件系统
线程锁: 防止多个线程同时修改进程内数据
进程锁:
当多个进程需要访问共享资源的时候,Lock可以用来避免访问的冲突
当多个进程同时使用同一份数据资源的时候,就会引发数据安全或顺序混乱问题
加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改
线程锁:
多线程使用共享资源时,不加锁会造成数据不安全。
GIL锁锁的是线程:、
保证同一时刻只有一个线程在运行。当A线程运行,拿到共享资源后,还没来得及处理,时间片切换到B线程,B线程拿到的是未处理的资源,因此造成数据不安全。需要加锁来避免线程间冲突
线程锁: 锁的是数据
指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
解决方法:递归锁(RLock):支持在同一线程中多次请求同一资源
Lock在同一个进程或者线程中,只能acquire一次,如两个acquire时,就会阻塞,产生死锁
RLock在同一个进程或者线程中,无论有多少个acquire都不会阻塞
但是acquire和release必须成对出现 n次acquire,需要n次release
同步与异步是线程之间的关系,两个线程之间要么是同步的,要么是异步的
同步操作时,调用者需要等待被调用者返回结果,才会进行下一步操作
而异步则相反,调用者不需要等待被调用者返回结果,即可进行下一步操作,被调用者通常依靠事件、回调等机制来通知调用者结果
单线程必定是同步操作
多线程可能是同步也可能是异步
例:
多线程中使用join, 则主线程和子线程是同步的, 子线程执行完毕后, 主线程才继续执行
多线程中未使用join, 子线程开启后,主线程立即往下执行,不需要等待子线程的执行结果
阻塞与非阻塞是对同一个线程来说的,在某个时刻,线程要么处于阻塞,要么处于非阻塞。
阻塞和非阻塞描述的是程序在等待调用结果(消息,返回值)时的状态
阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
例:
使用time.sleep 模拟IO,当前线程被挂起,IO结束后当前线程才继续往下执行
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
例:
线程中使用协程,遇到IO后,当前线程不会被挂起,会切换到其他协程继续工作
实现异步: 开启多线程
实现非阻塞:使用协程
同步阻塞方式:
发送方发送请求之后一直等待响应。
接收方处理请求时进行的IO操作如果不能马上等到返回结果,就一直等到返回结果后,才响应发送方,期间不能进行其他工作。
同步非阻塞方式:
发送方发送请求之后,一直等待响应。
接受方处理请求时进行的IO操作如果不能马上的得到结果,就立即返回,去做其他事情。
但是由于没有得到请求处理结果,不响应发送方,发送方一直等待。
当IO操作完成以后,将完成状态和结果通知接收方,接收方再响应发送方,发送方才进入下一次请求过程。(实际不应用)
异步阻塞方式:
发送方向接收方请求后,不等待响应,可以继续其他工作。
接收方处理请求时进行IO操作如果不能马上得到结果,就一直等到返回结果后,才响应发送方,期间不能进行其他操作。 (实际不应用)
异步非阻塞方式:
发送方向接收方请求后,不等待响应,可以继续其他工作。
接收方处理请求时进行IO操作如果不能马上得到结果,也不等待,而是马上返回去做其他事情。
当IO操作完成以后,将完成状态和结果通知接收方,接收方再响应发送方。(效率最高)