zoukankan      html  css  js  c++  java
  • python中实现并发的手段之 协程

    几种实现并发的手段

    进程 
       启动多个进程 进程之间是由操作系统负责调用
    线程
       启动多个线程 真正被CPU执行的最小单位实际是线程
    开启一个线程 创建一个线程 寄存器 堆栈
    关闭一个线程
    协程
    本质上是一个线程
    能够在多个任务之间切换来节省一些IO时间
    协程中任务之间的切换也消耗时间,但是开销要远远小于进程线程之间的切换

    通过生成器来实现的协程

    import time
    def consumer():
        while True:
            x = yield
            time.sleep(1)
            print('处理了数据 :',x)
    
    def producer():
      # 创建一个生成器对象 c
    = consumer()
      # 激活这个生成器 next(c)
    for i in range(10): time.sleep(1) print('生产了数据 :',i) c.send(i) producer()

    通过greenlet模块实现的协程

    真正的协程模块就是使用greenlet完成的切换
    from greenlet import greenlet
    def eat():
        print('eating start')
        g2.switch()
        print('eating end')
        g2.switch()
    
    def play():
        print('playing start')
        g1.switch()
        print('playing end')
    g1
    = greenlet(eat) g2 = greenlet(play) g1.switch()

    通过genevt模块实现的协程

    可以看出来,greenlet只能实现两个代码之间的切换,但是我们使用协程的主要原因是在IO请求时,达到非阻塞的作用,所以我们需要使用gevent模块来让代码可以遇到阻塞就自由的切换

    from gevent import monkey;monkey.patch_all()
    import time
    import gevent
    import threading
    def eat():
        print(threading.current_thread().getName())
        print(threading.current_thread())
        print('eating start')
        time.sleep(1)
        print('eating end')
    
    def play():
        print(threading.current_thread().getName())
        print(threading.current_thread())
        print('playing start')
        time.sleep(1)
        print('playing end')
    
    g1 = gevent.spawn(eat)
    g2 = gevent.spawn(play)
    g1.join()
    g2.join()

    同步和异步的性能比较

    进程和线程的任务切换由操作系统完成
    协程任务之间的切换由程序(代码)完成,只有遇到协程模块能识别的IO操作的时候,程序才会进行任务切换,实现并发的效果
    
    同步 和 异步
    from gevent import monkey;monkey.patch_all()
    import time
    import gevent
    
    def task(n):
        time.sleep(1)
        print(n)
    
    def sync():
        for i in range(10):
            task(i)
    
    def async():
        g_lst = []
        for i in range(10):
            g = gevent.spawn(task,i)
            g_lst.append(g)
        gevent.joinall(g_lst)  # for g in g_lst:g.join()
    
    sync()
    async()

    什么时候可以使用协程??

    在高IO的时候可以使用 例如爬虫, 爬虫需要请求很多url,使用协程可以让请求同时发出,而不会因为在等待一个url的请求响应而阻塞程序

    不适用于高计算的环境, 因为在计算时cpu是一直工作的, 频繁的切换运行的程序,会白白增加切换程序的时间,导致计算效率下降

    
    
    








  • 相关阅读:
    ldconfig和ldd用法
    Linux上ld和ld.so命令的区别
    一维二维码的提取、识别和产生
    最大轮廓和投影
    如何做出半透明和闪光效果
    马赫效应和应对方法
    钢管识别项目1
    钢管识别项目2
    选择轮廓(select_shape)
    压板识别项目分析
  • 原文地址:https://www.cnblogs.com/louyifei0824/p/9872001.html
Copyright © 2011-2022 走看看