zoukankan      html  css  js  c++  java
  • python并发编程

    并发编程相关概念

    # 进程
    """
    程序运行的过程,是操作系统资源分配的最小单位.资源分配的是cpu和内存的物理资源.
    进程号(PID):进程的号码,不同进程有不同的号码.进程之间,彼此隔离,通过socket通信
    """
    # 进程三状态: 就绪-----运行-----阻塞 (在阻塞状态下,等时间片到了时,转为运行状态)
    ​
    # 并发: 一个cpu同一时间执行多个任务
    ​
    # 并行: 多个cpu同一时间执行多个任务"""
    ​
    # cpu进程的调度方法:1, 先来的先执行  2, 短作业优先  3, 时间片轮转  4, 多级反馈
    ​
    # 同步: 一条主线,调用一个方法,要等这个方法执行结束,再开始下一个
    ​
    # 异步: 多条主线,不在一条主线上的方法,不关心,齐头并进
    

      

    1, 进程的基本使用

    # 获取进程号
    import
    os.getpid()                     # 获取当前进程号(子进程)
    os.getppid()                    # 获取父进程
    """父子是相对的
    pycharm    和     py
    那么pycharm是父进程,py文件是子进程
    py     和     func
    那么py文件是父进程, func 是子进程
    """
    # linux 命令
    ps -aux                         # 获取所有进程列表
    ps -aux | grep 进程号码          # 获取单独进程号进程具体信息
    kill -9 进程号码                 # 杀死进程号码进程
    

      

    1.1.1,在进程里边创建子进程

    import time,os
    from multiprocessing import Process
    ​
    # 曾经的代码
    def func():
        print(os.getpid(),"start")            # 29840 start
        time.sleep(1)                         
        print(os.getpid(),"end")              # 29840 end
    if __name__ == "__main__":
        func()
        print("主进程",os.getpid())            # 主进程 29840
        
    # 创建子进程
    def func():
        print(os.getpid(),"start")            # 29855 start
        time.sleep(1)
        print(os.getpid(),"end")              # 29855 end
    if __name__ == "__main__":
        p = Process(target = func)            # 创建一个即将要执行func函数的子进程对象
        p.start()                             # 异步开启子进程
        print("主进程",os.getpid())            # 主进程 29854
        
    """
    总结:
         曾经我们的代码时在一个主进程中,代码从上至下一次执行;今天,通过Process能够在
    主进程中再创建子进程,start()异步开启子进程,不关心这个进程结束没有,主进程继续执行
    而且,我们看到主进程一般情况要比子进程快一点,子进程的顺序却是不同的!(抢占cpu,谁快谁先执行)
    """
    

      

    1.1.2 带参数的子进程

    import time,os
    from multiprocessing import Process
    ​
    def func(n):
        time.sleep(0.5)
        print(n, "-----", os.getpid())
    ​
    if __name__ == "__main__":
        for i in range(10):
            p = Process(target=func, args=(i,))           # args接收参数,为元组!
            p.start()
        print("主进程", os.getpid())
    

      

    1.1.3 进程之间数据隔离

    # 主进程负责开启子进程,也负责回收子进程.主进程代码执行完毕,不代表主进程结束!如果不回收,则子进程称之为僵尸进程.几乎不存在,底层封装好了!
    count = 10
    def func():
        global count
        count += 1
        print("我是子进程count={}".format(count))
    ​
    if __name__ == "__main__":
        p=Process(target=func)
        p.start()                                           # 我是子进程count=11
        time.sleep(1)
        print(count)                                        # 10
    

      

    1.1.4 多进程异步并发

    def func(n):
        print("数字{}<=>1.子进程id>>{},2父进程id>>{}".format(n,os.getpid(),os.getppid()))
    ​
    if __name__ == "__main__":
        for i in range(1,11):
            Process(target=func,args=(i,)).start()
            
        print("主进程执行结束了....",os.getpid())
    

      

    1.1.5 join 同步子父进程

    # 只有一个子进程时
    def func():
        time.sleep(0.5)
        print("子进程", os.getpid())
    ​
    if __name__ == "__main__":
        p = Process(target=func)
        p.start()                   # 异步,非阻塞
        p.join()                    # 同步阻塞
        print("主进程", os.getpid())
    """
    如果没有p.join(),先打印"主进程",再打印"子进程"
    p.join()后,会等子进程结束后在执行主进程
    """
    ​
    # 多个子进程怎么执行呢?
    ​
    def func(n):
        time.sleep(0.5)
        print(n, "-----", os.getpid())
    ​
    if __name__ == "__main__":
        lst = []
        for i in range(10):
            p = Process(target=func, args=(i,))
            p.start()         
            lst.append(lst)
            
        for j in lst:
            p.join()                  # 已结束的进程相当于pass,没有执行的进行阻塞
        print("主进程", os.getpid())
    

      

    1.1.6 守护进程

    """
    守护进程守护的是主进程,如果主进程中的所有代码执行完毕了,
    当前这个守护进程会被立刻杀死,立刻终止.
    语法:
    进程.daemon = True 设置当前这个进程为守护进程
    必须写在start()调用进程之前进行设置
    默认:主进程会默认等待所有子进程执行结束之后,在关闭程序,释放资源
    """
    def func1():
        count = 1
        while True:
            print("*" * count)
            time.sleep(0.5)
            count += 1
            
    def func2():
        print("start func2 当前子进程任务")
        time.sleep(3)
        print("end   func2 当前子进程任务")
    ​
    if __name__ == "__main__":
        p1 = Process(target=func1)
        p2 = Process(target=func2)
        # 设置p1这个进程对象为守护进程
        p1.daemon = True
        
        p1.start()
        p2.start()
        
        time.sleep(1)
        print("主进程执行结束 ... ")
    

      

    1.1.7 面向对象创建子进程

    class MyProcess(Process):
        def __init__(self,arg):
            # 手动调用一下父类的构造方法(最终实现进程的创建)
            super().__init__()
            self.arg = arg
    ​
        def run(self):  
            print("1.子进程id>>{},2父进程id>>{}".format(os.getpid(),os.getppid()))
            print(self.arg)
        
    if __name__ == "__main__":
        p = MyProcess("我是传进来的参数")
        p.start()
        print("3.子进程id>>{},4父进程id>>{}".format(os.getpid(),os.getppid()))
    

      

    1.2 Lock & Semaphore 进程锁

    """
    如果不上锁,执行代码,我们会发现,只有一张票的情况下,3个人却都买到了票:
    异步并发,会造成数据混乱!
    """
    import json,time
    from multiprocessing import Process
    ​
    def w_r_info(mod,dic=None):
        if mod == "r":
            with open("12306",mode=mod,encoding='utf-8') as f:
                dic = json.load(f)
                return dic
        else:
            with open("12306",mode=mod,encoding='utf-8') as f:
                json.dump(dic,f)
    ​
    def func_12306(name):
        info = w_r_info("r")
        print("%s查看了余票,还剩%s张"%(name,info["count"]))
        if info["count"] > 0 :
            info["count"] -= 1
            time.sleep(1)
            w_r_info("w",info)
            print("%s买到了票" % (name))
            
        else:print("%s没有买到票" % (name))
    if __name__ == '__main__':
        lst = ["赵一","钱二","sun3"]
        for i in lst:
            p = Process(target=func_12306,args=(i,))
            p.start()
    

      

    1.2.1 Lock

    # 一把锁 Lock 改造(模拟12306)
    import json,time
    from multiprocessing import Process,Lock
    ​
    def w_r_info(mod,dic=None):
        if mod == "r":
            with open("12306",mode=mod,encoding='utf-8') as f:
                dic = json.load(f)
                return dic
        else:
            with open("12306",mode=mod,encoding='utf-8') as f:
                json.dump(dic,f)
    ​
    def func_12306(name,lock):
    ​
        info = w_r_info("r")                            # 读余票
        print("%s查看了余票,还剩%s张"%(name,info["count"]))
        time.sleep(0.5)
        lock.acquire()                                  # 上锁,后面人进来就是修改过的值
        info = w_r_info("r")                            # 读余票
        if info["count"] > 0 :
            info["count"] -= 1
            w_r_info("w",info)
            print("%s买到了票" % (name))
            # lock.release()
        else:print("%s没有买到票" % (name))
        lock.release()                                   # 解锁
    if __name__ == '__main__':
        lock = Lock()                                    # 创建一把锁
        lst = ["赵一","钱二","sun3"]
        for i in lst:
            p = Process(target=func_12306,args=(i,lock))
            p.start()
    

      

    1.2.2 Semaphore

    # 多把锁
    import time
    from multiprocessing import Process,Semaphore
    def func(n,sem):
        with sem:
            time.sleep(1)
            print("%s在拉屎"%(n))
    ​
    if __name__ == '__main__':
        lst = ["赵一","钱二","孙三","李四","周五","吴六","郑七","王八"]
        sem = Semaphore(1)                  # 相当于指定多少个人同时拉屎
        for i in lst:
            p = Process(target=func,args=(i,sem))
            p.start()
    

      

    1.3 Event 进程事件

    """
    # 阻塞事件 :
        e = Event()生成事件对象e   
        e.wait()动态给程序加阻塞 , 程序当中是否加阻塞完全取决于该对象中的is_set() [默认返回值是False]
        # 如果是True  不加阻塞
        # 如果是False 加阻塞
    ​
    # 控制这个属性的值
        # set()方法     将这个属性的值改成True
        # clear()方法   将这个属性的值改成False
        # is_set()方法  判断当前的属性是否为True  (默认上来是False)
    """
    ​
    # 红绿灯解释进程事件
    import time,random
    from multiprocessing import Process,Event
    ​
    def light(e):
        print("红灯!")
        while True:
            if e.is_set():       # 1,is_set() 默认值是 False  阻塞
                time.sleep(2)    # 4,等待绿灯2秒,变为红灯
                print("红灯!")
                e.clear()        # 5,设置is_set()为 False  阻塞
            else:
                time.sleep(2)    # 2,等待红灯2秒
                print("绿灯!")
                e.set()          # 3,设置is_set()为True   ,放行
    ​
    def car(e,i):
        # 格式一定,因为当红灯时,小车进来等待红灯,wait阻塞,当绿灯时继续执行代码,如果反过来,红灯等待,阻塞,当绿灯时,这个程序已经结束了,同行不了
        if not e.is_set():
            time.sleep(random.uniform(0.3,0.8))         
            print(i,"等待红灯中")
            e.wait()
        print(i,"通行了")
    ​
    if __name__ == '__main__':
        e = Event()
        lst= []
        p1 = Process(target=light, args=(e,))
        p1.daemon = True
        p1.start()
    ​
        for i in range(10):
            p2 = Process(target=car,args=(e,i))
            time.sleep(1)
            p2.start()
            lst.append(p2)
        for i in lst:
            p2.join()
        print("主程序结束")
    

      

    1.4 Queue 进程队列

    # 进程之间的通信 IPC (inter process communication)
    from multiprocessing import Queue
    q = Queue()             # 创建一个队列对象,可以设置队列长度
    q.put(值)               # 往队列对象里放值
    q.get()                 # 从队列对象里取值
    """
    队列特点: 先进先出,后进后出
    1,如果超过了队列的指定长度,在继续存值会出现阻塞
    2,队列中如果已经没有数据了,在调用get会发生阻塞
    """
    q.put_nowait()          # 非阻塞版本的put,超出长度后,直接报错
    q.get_nowait()          # 如果没有值会报错,windows好使,可以使用try抑制报错
    

      

    1.4.1 进程之间数据共享

    from multiprocessing import Process,Queue
    def func(p):
        p.put("我爱你")                     # 子进程放值
    ​
    if __name__ == '__main__':
        p = Queue()
        pro = Process(target=func,args=(p,))
        pro.start()
        pro.join()
        print(p.get())                      # 主进程取值
    

      

    1.4.1.1 Manager 字典,列表共享数据

    from multiprocessing import Manager,Process
    def func(dic):
        print(dic)
    ​
    if __name__ == '__main__':
        m = Manager()
        dic = m.dict({"name":"bajie"})
        Process(target=func,args=(dic,)).start()
        time.sleep(1)            # 共享数据必须慢一点
        print(dic,'--------')
    

      

    1.4.2 生产者与消费者模型

    # 消费者模型
    def consumer(q,name):
        while True:
            food = q.get()
            if food is None:
                break
            time.sleep(random.uniform(0.1,1))
            print("%s 吃了一个%s" % (name,food))
        
    # 生产者模型
    def producer(q,name,food):
        for i in range(5):
            time.sleep(random.uniform(0.1,1))
            # 打印生产的数据
            print("%s 生产了 %s%s" % (name,food,i))
            # 存储生产的数据
            q.put(food + str(i))
    ​
    if __name__ == "__main__":
        q = Queue()
        p1 = Process(target=consumer,args=(q,"宋云杰"))
        p2 = Process(target=producer,args=(q,"马生平","黄瓜"))
        p1.start()
        p2.start()
        # 在生产者生产完所有数据之后,在队列的末尾添加一个None
        p2.join()
        q.put(None)
    

      

    1.4.3 生产者与消费者模型升级版 (JoinableQueue)

    from multiprocessing import Process, JoinableQueue
    import time,random
    """
    put 存储
    get 获取
    task_done 
    join
    ​
    task_done 和 join 配合使用的
    队列中 1 2 3 4 5
    put 一次 内部的队列计数器加1
    get 一次 通过task_done让队列计数器减1
    join函数,会根据队列计数器来判断是阻塞还是放行
        队列计数器  = 0 , 意味着放行
        队列计数器 != 0 , 意味着阻塞
    """
    ​
    # 1.基本语法
    """
    jq =JoinableQueue()
    jq.put("a")
    print(jq.get())
    # 通过task_done让队列计数器减1
    jq.task_done()
    jq.join()
    print("finish")
    """
    ​
    # 2.改造生产者和消费者模型
    def consumer(q,name):
        while True:
            food = q.get()
            time.sleep(random.uniform(0.1,1))
            print("%s 吃了一个%s" % (name,food))
            # 当队列计数器减到0的时,意味着进程队列中的数据消费完毕
            q.task_done()
        
    # 生产者模型
    def producer(q,name,food):
        for i in range(5):
            time.sleep(random.uniform(0.1,1))
            # 打印生产的数据
            print("%s 生产了 %s%s" % (name,food,i))
            # 存储生产的数据
            q.put(food + str(i))
        
    ​
    if __name__ == "__main__":
        q =JoinableQueue()
        # 消费者
        p1 = Process(target=consumer,args=(q,"宋云杰"))
        # 生产者
        p2 = Process(target=producer,args=(q,"马生平","黄瓜"))
        
        # 设置p1消费者为守护进程
        p1.daemon = True
        p1.start()
        p2.start()
        
        # 把所有生产者生产的数据存放到进程队列中
        p2.join()
        # 为了保证消费者能够消费完所有数据,加上队列.join
        # 当队列计数器减到0的时,放行,不在阻塞,程序彻底结束.
        q.join()
        print("程序结束 ... ")
    

      

    2, 线程的基本使用

    """
    cpu执行程序的最小单位.
    进程与线程的关系:  1,进程是资源,线程是工人    2,一个进程至少有一个线程
    """
    

      

    2.1 创建多线程

    from threading import Thread,currentThread
    ​
    currentThread().ident           # 获取线程号
    def func():
        print("当前线程ID:%s"%(currentThread().ident))
        
    if __name__ == '__main__':
        t = Thread(target=func).start()
        print("当前线程ID:%s" % (currentThread().ident))
    

      

    2.1.1 进程与线程谁的速度快?

    # 测试线程速度    1000个大概0.5秒
    import time
    from threading import Thread,currentThread
    ​
    def func():
        print("当前线程ID:%s"%(currentThread().ident))
    ​
    if __name__ == '__main__':
        lst = []
        a = time.time()
        for i in range(1000):
            t = Thread(target=func)
            t.start()
            lst.append(t)
        for i in lst:
            i.join()
        b = time.time()
        print("用了{}秒".format(b-a))
        
    # 测试进程速度    1000个大概5秒
    from multiprocessing import Process
    ​
    def func():
        print("当前线程ID:%s"%(currentThread().ident))
    ​
    if __name__ == '__main__':
        lst = []
        a = time.time()
        for i in range(1000):
            t = Process(target=func)
            t.start()
            lst.append(t)
        for i in lst:
            i.join()
        b = time.time()
        print("用了{}秒".format(b-a))
    

      

    2.1.2 线程共享进程资源

    from threading import Thread
    ​
    num = 520
    def func():
        global num
        num -= 1
    ​
    if __name__ == '__main__':
        t = Thread(target=func)
        t.start()
        t.join()
        
        print(num)           # 519
    

      

    2.1.3 线程的相关函数

    import time
    from threading import Thread,currentThread,enumerate
    from multiprocessing import Process
    ​
    def func():
        time.sleep(1)
    ​
    if __name__ == '__main__':
        t = Thread(target=func)
        t.start()
        print(t.is_alive())                  # 获取线程存活状态
        t.setName("爬树据")                   # 设置线程名字
        print(t.getName())                   # 获取线程名字
        print(currentThread().ident)         # 获取线程ID
        print(enumerate())                   # 获取存活线程的列表
    

      

    2.2 守护线程

    # ### 守护线程 : 等待所有线程全部执行完毕之后,自己在终止,守护所有线程
    ​
    from threading import Thread
    import time
    def func1():
        while True:
            time.sleep(0.5)
            print("我是func1")
    ​
    def func2():
        print("我是func2 start ... ")
        time.sleep(3)
        print("我是func2 end ... ")
    ​
    def func3():
        print("我是func3 start ... ")
        time.sleep(5)
        print("我是func3 end ... ")
    ​
    if __name__ == "__main__":
        t1 = Thread(target=func1)
        t2 = Thread(target=func2)
        t3 = Thread(target=func3)
        
        # 在start调用之前,设置线程为守护线程
        t1.setDaemon(True)
        
        t1.start()
        t2.start()
        t3.start()
        
        print("主线程执行结束 .... ")
    

      

    2.3 线程中的数据安全

    2.3.1 Lock锁

    # 一把锁
    from threading import Thread,Lock
    ​
    n = 0
    def add(lock):
        global n
        with lock:
            for i in range(1000000):
                n += 1
    def rem(lock):
        global n
        with lock:
            for i in range(1000000):
                n -= 1
    if __name__ == "__main__":
        lst = []
        lock = Lock()
        t1 = Thread(target = add,args=(lock,))
        t2 = Thread(target = rem,args=(lock,))
        t1.start()
        t2.start()
        lst.append(t1)
        lst.append(t2)
        for i in lst:
            i.join()
        print(n)
    

      

    2.3.2 Semaphore 信号量

    # 信号量 Semaphore
    """
    再创建线程的时候是异步创建
    在执行任务时,遇到Semaphore进行上锁,会变成同步程序
    """
    from threading import Semaphore , Thread
    import time
    ​
    def func(i,sm):
        with sm:
            print(i)
            time.sleep(3)   
    if __name__ == "__main__":
        # 支持同一时间,5个线程上锁
        sm = Semaphore(5)
        for i in range(20):
            Thread(target=func,args=(i,sm)).start()
    

      

    2.3.3 递归锁 Rlock

    # 语法死锁
    from threading import Lock
    lock = Lock()
    lock.acquire()
    lock.acquire()
    lock.acquire()
    ​
    lock.release()
    ​
    # 逻辑死锁
    多把锁,
    ​
    # 递归锁
    # (3) 递归锁的使用
    """
    递归锁专门用来解决这种死锁现象,临时用于快速解决线上项目发生阻塞死锁问题的
    """
    rlock = RLock()
    rlock.acquire()
    rlock.acquire()
    rlock.acquire()
    rlock.acquire()
    print(112233)
    rlock.release()
    rlock.release()
    rlock.release()
    rlock.release()
    ​
    print("程序结束 ... ")
    # 依然可以执行
    

      

    2.4 Event 事件

    from threading import Thread
    ​
    # 模拟链接远程数据库
    def check(e):
        # 用一些延迟来模拟检测的过程
        time.sleep(random.randrange(1,6)) # 1 2 3 4 5
        # time.sleep(1)
        print("开始检测链接用户的合法性")
        e.set()
        
    def connect(e):
        sign = False
        for i in range(1,4): # 1 2 3    
            e.wait(1)   
            if e.is_set():
                print("数据库链接成功 ... ")
                sign = True
                break
            else:
                print("尝试链接数据库第%s次失败 ... " % (i))
                
        if sign == False:
            raise TimeoutError
            
    e = Event()
    Thread(target=connect,args=(e,)).start()
    Thread(target=check,args=(e,)).start()
    

      

    2.5 线程队列 PriorityQueue

    from queue import Queue
    # Queue (先进先出,后进后出)
    ​
    from queue import LifoQueue
    # LifoQueue(先进后出,后进先出)
    ​
    方法与进程队列相同
    put()
    get()
    put_nowait()
    get_nowait()
    ​
    from queue import PriorithQueue
    # 优先级队列
    """
    1,按照ascii码排序输出, 2,不可以存放不同的数据类型
    """
    

      

    3, 池 Pool

    3.1 进程池 & 线程池

    # 引入模块
    from concurrent.futures import ProcessPoolExecutor       # 进程池
    from concurrent.futures import ThreadPoolExecutor        # 线程池
    from threading import current_thread
    print(current_thread().ident)                            # 线程号
    import os
    print(os.getpid())                                       # 进程号
    print(os.cpu_count())                                    # cpu逻辑数
    ​
    # 进程池的基本使用
    def func(i):
        print(i,"start...进程号:",os.getpid())
        time.sleep(0.1)
        print(i,"end.....进程号:",os.getpid())
        return os.getpid()
    ​
    if __name__ == '__main__':
        setvar = set()
        lst = []
        # 创建进程池,默认为cpu逻辑数,
        p = ProcessPoolExecutor(30)
        # 异步提交任务  ---->  p.submit(func,i)
        for i in range(30):
            # 可以拿到返回值,是一个对象
            res = p.submit(func,i)
            lst.append(res)
        for i in lst:
            # result() 获取返回值,同步阻塞
            setvar.add(i.result())
        print(setvar,len(setvar))
    ​
        
    # 线程池的基本使用
    def func(i):
        print(i,"start...线程号:",current_thread().ident)
        time.sleep(1)
        print(i,"end.....进程号:",os.getpid())
        # time.sleep(1)
        print(i, "end.....进程号:%s,线程号:%s"%(os.getpid(),current_thread().ident) )
        return current_thread().ident
    ​
    if __name__ == '__main__':
        setvar = set()
        lst = []
        # 创建进程池,默认为cpu逻辑数,
        p = ThreadPoolExecutor(60)
        # 异步提交任务  ---->  p.submit(func,i)
        for i in range(60):
            # 可以拿到返回值,是一个对象
            res = p.submit(func,i)
            lst.append(res)
        for i in lst:
            # result() 获取返回值,同步阻塞
            setvar.add(i.result())
        print(setvar,len(setvar))
       
    

      

    3.1.1 线程池 map 的使用

    def func(i):
        time.sleep(5)
        print(i, "end.....进程号:%s,线程号:%s"%(os.getpid(),current_thread().ident) )
        return current_thread().ident
    ​
    if __name__ == '__main__':
        setvar = set()
        lst = []
        # 创建线程池,(最大允许并发5个线程)
        p = ThreadPoolExecutor(5)
        it = p.map(func,range(20))
        p.shutdown()
    ​
        for i in lst:
            print(i)
    

      

    3.1.2 回调函数

    from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
    from threading import current_thread  as cthread
    import os,time
    ​
    # 返回值对象.add_done_callback(回调函数)
    ​
    def func1(i):
        print("process start ... " , os.getpid())
        time.sleep(1)
        print("process end ... ", i)
        return "*" * i
    ​
    def func2(i):
        print("thread start ... " , cthread().ident)
        time.sleep(1)
        print("thread end ... ", i)
        return "*" * i
    ​
    def call_back1(obj):
        print("<===回调函数callback进程号===>" , os.getpid())
        print(obj.result())
        
    def call_back2(obj):
        print("<===回调函数callback线程号===>" ,cthread().ident)
        print(obj.result())
    ​
    # (1) 进程池的回调函数: 由主进程执行调用完成的
    ​
    if __name__ == "__main__":
        p = ProcessPoolExecutor()
        for i in range(1,11):
            res = p.submit(func1,i)
            # print(res.result())
            res.add_done_callback(call_back1)
            # self.func(func2)
        p.shutdown()
        print("主进程执行结束 ... " , os.getpid())
    ​
    ​
    # (2) 线程池的回调函数 : 由当前子线程调用完成的
    if __name__ == "__main__":
        tp = ThreadPoolExecutor(5)
        for i in range(1,11):
            res = tp.submit(func2,i)
            res.add_done_callback(call_back2)
            
        tp.shutdown()
        print("主线程执行结束 ... " , cthread().ident)
    

      

     

    4, 协程

    # 能够在一个线程中多个任务(函数)之间来回切换,那么每个任务都是协程
    ​
    # 线程与协程的区别:
        线程:操作系统切换,开销大,操作系统不可控,让操作系统的压力的大,操作系统对IO(细微的阻塞)操作更加敏感
        协程:prthon代码切换,开销小,用户可控,不会增加操作系统的压力。在用户层面,对细微的阻塞的感知相对较低(open,print)
    

      

    4.1 协程基本操作

    import time,gevent
    def func():
        print("1")
        time.sleep(2)               # 操作系统阻塞,协程不识别,不会切换任务
        print("2")
    ​
    g = gevent.spawn(func)           # 创建协程任务
    gevent.sleep(3)                  # 协程阻塞
    print(3)
    ​
    # 识别所有阻塞,底层覆盖
    from gevent import monkey
    monkey.patch_all()
    ​
    # 阻塞所有任务
    g.joinall(list(协程对象))
    ​
    # 查看g协程任务返回值
    g.value
     
    

      

  • 相关阅读:
    数组的Clone方法
    反射创建类的一种方法
    css比较容易搞混的三个选择器
    java8 引进lamda
    js动态创建的元素绑定事件
    【Alpha版本】项目测试
    第五次团队作业——【Alpha版本】随笔汇总
    【Alpha版本】项目总结
    【Alpha版本】冲刺阶段——Day 10
    【Alpha版本】冲刺阶段——Day 9
  • 原文地址:https://www.cnblogs.com/zhoulangshunxinyangfan/p/13550160.html
Copyright © 2011-2022 走看看