PythonConcurrent

进程,线程,协程

进程/线程/协程

进程:

资源分配的最小单位。是程序在处理机上的一次执行过程。进程间相互独立,内存隔离,一个进程修改数据不会影响其他进程

线程:

是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

进程/线程之间如何进行通信

进程之间通信方式:(IPC)—队列和管道

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互斥锁:

进程锁:
   
    当多个进程需要访问共享资源的时候,Lock可以用来避免访问的冲突
    当多个进程同时使用同一份数据资源的时候,就会引发数据安全或顺序混乱问题
    加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改

线程锁:
    多线程使用共享资源时,不加锁会造成数据不安全。

线程中有了GIL锁为什么还要加线程锁?

GIL锁锁的是线程:、
    保证同一时刻只有一个线程在运行。当A线程运行,拿到共享资源后,还没来得及处理,时间片切换到B线程,B线程拿到的是未处理的资源,因此造成数据不安全。需要加锁来避免线程间冲突

线程锁: 锁的是数据	

死锁与递归锁:

指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。

解决方法:递归锁(RLock):支持在同一线程中多次请求同一资源
Lock在同一个进程或者线程中,只能acquire一次,如两个acquire时,就会阻塞,产生死锁
RLock在同一个进程或者线程中,无论有多少个acquire都不会阻塞
但是acquire和release必须成对出现 n次acquire,需要n次release 

Sync/Async

同步(Sync)和异步(Async)(线程间调用)

同步与异步是线程之间的关系,两个线程之间要么是同步的,要么是异步的

同步操作时,调用者需要等待被调用者返回结果,才会进行下一步操作

而异步则相反,调用者不需要等待被调用者返回结果,即可进行下一步操作,被调用者通常依靠事件、回调等机制来通知调用者结果

单线程必定是同步操作
多线程可能是同步也可能是异步

例:
  
  多线程中使用join, 则主线程和子线程是同步的, 子线程执行完毕后, 主线程才继续执行
  
  多线程中未使用join, 子线程开启后,主线程立即往下执行,不需要等待子线程的执行结果

阻塞与非阻塞(线程内调用)

阻塞与非阻塞是对同一个线程来说的,在某个时刻,线程要么处于阻塞,要么处于非阻塞。

阻塞和非阻塞描述的是程序在等待调用结果(消息,返回值)时的状态

阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。

例:
    使用time.sleep 模拟IO,当前线程被挂起,IO结束后当前线程才继续往下执行

非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。

例:
    线程中使用协程,遇到IO后,当前线程不会被挂起,会切换到其他协程继续工作

实现方式:

实现异步: 开启多线程

实现非阻塞:使用协程

实例:

同步阻塞方式:
    
    发送方发送请求之后一直等待响应。
    
    接收方处理请求时进行的IO操作如果不能马上等到返回结果,就一直等到返回结果后,才响应发送方,期间不能进行其他工作。

同步非阻塞方式:
    
    发送方发送请求之后,一直等待响应。
    
    接受方处理请求时进行的IO操作如果不能马上的得到结果,就立即返回,去做其他事情。
    但是由于没有得到请求处理结果,不响应发送方,发送方一直等待。
    
    当IO操作完成以后,将完成状态和结果通知接收方,接收方再响应发送方,发送方才进入下一次请求过程。(实际不应用)

异步阻塞方式:
    
    发送方向接收方请求后,不等待响应,可以继续其他工作。
    
    接收方处理请求时进行IO操作如果不能马上得到结果,就一直等到返回结果后,才响应发送方,期间不能进行其他操作。 (实际不应用)

异步非阻塞方式:
    
    发送方向接收方请求后,不等待响应,可以继续其他工作。
    
    接收方处理请求时进行IO操作如果不能马上得到结果,也不等待,而是马上返回去做其他事情。
    当IO操作完成以后,将完成状态和结果通知接收方,接收方再响应发送方。(效率最高)