day 35 GIL全局解释器 多线程和多进程 死锁和递归 协程

今日内容:

二、内容:

1、生产者消费者模型补充

from multiprocessing import Process,Queue
import time,random,os

def producer(name,food,q):
    for i in range(3):
        res="%s%s"%(food,i)
        time.sleep(0.5)
        q.put(res)
        print("%s 生产了%s"%(name,res))

def consumer(name,q):
    while True:
        res=q.get()
        if res is None:
           break
        print("%s 吃 %s"%(name,res))
        time.sleep(random.randint(2,3))
if __name__=="__main__":
    q=Queue()
    p1=Process(target=producer,args=("egon1","包子1",q,))
    p2=Process(target=producer,args=("egon2","包子2",q,))
    p3=Process(target=producer,args=("egon3","包子3",q,))
    c1=Process(target=producer,args=("alex",q,))
    c2=Process(target=producer,args=("wxx",q,))

    p1.start()
    p2.start()
    p3.start()
    c1.start()
    c2.start()

    p1.join()
    p2.join()
    p3.join()
    q.put(None)
    q.put(None)
    print("")
生产者消费者比较LOW 的写法

查看python进程

利用守护进程来实现  生产者和消费者模型

from multiprocessing import Process,Queue,JoinableQueue
import time,random,os

def producer(food,q):
    for i in range(3):
        res="%s%s"%(food,i)
        time.sleep(0.5)
        q.put(res)
        print("%s 生产了 %s"%(os.getpid(),res))
    q.join()

def consumer(q):
    while True:
        res=q.get()
        print("%s 吃 %s"%(os.getpid(),res))
        time.sleep(random.randint(2,3))
        q.task_done()

if __name__=="__main__":
    q=JoinableQueue()
    p1=Process(target=producer,args=("包子",q,))
    p2=Process(target=producer,args=("烤鸡",q,))
    p3=Process(target=producer,args=("gouliang",q,))
    c1=Process(target=consumer,args=(q,))
    c2=Process(target=consumer,args=(q,))

    c1.daemon=True
    c2.daemon=True

    p1.start()
    p2.start()
    p3.start()
    c1.start()
    c2.start()

    p1.join()
    p2.join()
    p3.join()
#生产者结束--->q.join()--->消费者确实把所有的数据都收到
    print('', os.getpid())
生产者和消费者模型 新

2、GIL解释器锁(就是一把互斥锁)

 (1)互斥锁就是为了保护数据

(2)Cpython解释器中,统一进程下来气的多线程,统一时刻只能有一个线程执行,无法使用多核优势

(3)8个线程可以被8个cpu执行,可以有两个进程,每个进程里面有四个线程,同一时间只能有一个线程被执行

(4)pyhton的多线程没办法用到多核优势木业没有办法用到并行,但是可以用到并发

(5)多核(cpu)的优势:运行快,计算快,cpu的功能是计算,遇到I/O没有什么用处

(6)python的多线程有什么特点(重要)

  1、cpython的解释器由于GIL解释器锁的存在,导致基于cpython解释器写出来的多线程

    统一时间只能有一个线程出来运行,不能用上多核优势

  2、多核带来了什么好处?计算速度快,遇到I/O多核没有什么用处

(7)开进程开销大,开进程对于多核优势没有什么用处

解释:

  (1)在python中所有的数据都是共享的

  (2)python解释器只是一个软件,给你提供代码的运行解释并执行

  (3)假如线程可以利用多核优势:

    1、垃圾回收线程就会与其他的线程产生矛盾(因为是并行运行,垃圾回收线程机制就不会有用处)

    2、垃圾回收机制是Python解释器的优势相对于其他的语言

 3、GIL全局解释器锁

  (1)用锁的目的是为了让局部串行,其余的还是并发执行

  (2)GIL锁是保护垃圾回收机制有关的解释器的数据

4、多进程和多线程的应用场景

  (1)python多进程用不到多核(纯I/O进程)

 (2)python多进程中多核是有用的(对于多计算型)

(3)计算型

     线程要比进程花费时间长(线程不能串行,可以并发执行 来回切换)

#计算密集型

from multiprocessing import Process
from threading import Thread
import os,time
def work():
    res=0
    for i in range(10000000):
        res*=1
if __name__=="__main__":
    l=[]
    print(os.cpu_count())  #本机为四核
    start=time.time()
    for i in range(4):
        # p=Process(target=work) #耗时为run time is 2.872164249420166
        p=Thread(target=work) #耗时为run time is 6.84939169883728
        l.append(p)
        p.start()
    for p in l:
        p.join()
    stop=time.time()
    print("run time is %s"%(stop-start))
计算密集型

(4)I/O型,线程要比进程花费时间短(进程的开销大)

5、死锁现象与递归锁

(1)死锁

(2)递归锁(解决死锁的方式)

import time
mutexA=mutexB=RLock()
# mutexA=mutexB=Lock()

class Mythread(Thread):
    def run(self):
        self.f1()
        self.f2()

    def f1(self):
        mutexA.acquire()
        print("%s 拿到A锁"%self.name)

        mutexB.acquire()
        print("%s 拿到B锁"%self.name)
        mutexB.release()

        mutexA.release()

    def f2(self):
        mutexB.acquire()
        print("%s 拿到B锁"%self.name)
        time.sleep(0.1)
        mutexA.acquire()
        print("%s 拿到A锁"%self.name)
        mutexA.release()

        mutexB.release()

if __name__=="__main__":
    for i in range(10):
        t=Mythread()
        t.start()
死锁与递归锁

6、协程

(1)单线程下实现并发叫协程
(2)只有遇到I/O切了才有意义(提升效率)
(3)要实现单线程情况下的并发 要本着
1、串行执行(没有切换,创建列表会有开销 可以忽略不计,数据UI越大 超过一定范围之后,
列表的开销会增大)

import time
def consumer(res):
    """任务1:接收数据,处理数据"""
    pass
def producer():
    """任务2:生产数据"""
    res=[]
    for i in range(100000):
        res.append(i)
    return res
start=time.time()
#串行执行
res=producer()
consumer(res)
stop=time.time()
print(stop-start)
串行执行
import time
def consumer():
    """任务1:接收数据,处理数据"""
    while True:
        x=yield
        print("consumer")
def producer():
    """任务2:生产数据"""
    g=consumer()
    next(g)
    for i in range(10000):
        print("producer")
        time.sleep(6)
        g.send(i)
start=time.time()
#基于yield保存状态,实现两个任务直接来回切换,即并发的效果
#ps :如果每个任务中都加上打印,那么明显看到两个任务的打印是你一次我一次
#即并发执行的
producer()
stop=time.time()
print(stop-start)
并发执行

7、gevent模块  (明天讲)

原文地址:https://www.cnblogs.com/number1994/p/8195144.html