• 并发编程(二) 进程、协程


    三 Python进程

    3.1 multiprocessing类对象

    from multiprocessing import Process
    
    
    def bar(i):
        print('hello NO.{0}'.format(i))
    
    
    for i in range(10):
        p = Process(target=bar, args=(i,))
        p.start()
    

    ps:由于进程之间的数据需要各自持有一份,所以创建进程需要的非常大的开销。

    multiprocessing的特点:

    • Python中的多进程管理模块是multiprocessing模块。
    • 通过multiprocessing.Process来创建一个进程对象,Process对象与Thread对象的用法相同,也有start(), run(), join()的方法。
    • multiprocessing与threading一样,调用同一套API。

    3.2 进程间通讯

    。。。

    四 协程

    与一个进程可以包含多个线程一样,一个程序可以包含多个协程,因而下面我们来比较协程和线程。

    我们知道多个线程相对独立,有自己的上下文,切换受系统控制;
    而协程也相对独立,有自己的上下文,但是其切换由自己控制,例如,A协程切换到B协程是由A协程来控制的。

    协程原理:

    协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。
    因此,协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。

    4.1 yield实现协程

    协程的特点:

    • 协程是单线程,不能再切换
    • 不再有任何锁的概念

    整个流程无锁,由一个线程执行,produce和consumer协作完成任务,所以称为“协程”,而非线程的抢占式多任务。

    import time
    
    def consumer():
        r = ''
        while True:
            n = yield r
            if not n:
                return
            print('[CONSUMER] ←← Consuming %s...' % n)
            time.sleep(1)
            r = '200 OK'
    
    def produce(c):
        next(c)
        n = 0
        while n < 5:
            n = n + 1
            print('[PRODUCER] →→ Producing %s...' % n)
            cr = c.send(n)
            print('[PRODUCER] Consumer return: %s' % cr)
    
        c.close()
    
    if __name__ == '__main__':
        c = consumer()
        produce(c)
    

    原理:
    生成器函数或者协程函数中的yield语句挂起函数的执行,直到稍后使用next()或send()操作进行恢复为止。

    4.2 greenlet

    greenlet机制的主要思想:
    可以使用一个调度器循环在一组生成器函数之间协作多个任务。
    greenlet是python中实现我们所谓的"Coroutine(协程)"的一个基础库.

    特点:

    • 方便手动切换

    调用switch()方法,进行切换

    from greenlet import greenlet
     
    def test1():
        print (12)
        gr2.switch()
        print (34)
        gr2.switch()
     
    def test2():
        print (56)
        gr1.switch()
        print (78)
     
    gr1 = greenlet(test1)
    gr2 = greenlet(test2)
    gr1.switch()
    

    4.3 gevent

    gevent是第三方库,通过greenlet实现协程。

    原理:
    当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。

    特点:

    • 自动切换

    监听IO,实现自动切换

    import gevent
    import time
    
    def foo():
        print("running in foo")
        gevent.sleep(2)
        print("switch to foo again")
    
    def bar():
        print("switch to bar")
        gevent.sleep(5)
        print("switch to bar again")
    
    start=time.time()
    
    gevent.joinall( #启动函数
        [gevent.spawn(foo),
        gevent.spawn(bar)]
    )
    
    print(time.time()-start)
    

    ps:由于切换是在IO操作时自动完成,所以gevent需要修改Python自带的一些标准库,这一过程在启动时通过monkey patch完成:

    from gevent import monkey
    monkey.patch_all()
    import gevent
    from urllib import request
    import time
    
    def f(url):
        print('GET: %s' % url)
        resp = request.urlopen(url) #urlopen去页面取出页面内容,起到IO作用
        data = resp.read()
        print('%d bytes received from %s.' % (len(data), url))
    
    start=time.time()
    
    gevent.joinall([
            gevent.spawn(f, 'https://itk.org/'),
            gevent.spawn(f, 'https://www.github.com/'),
            gevent.spawn(f, 'https://zhihu.com/'),
    ])
    
    # f('https://itk.org/')
    # f('https://www.github.com/')
    # f('https://zhihu.com/')
    
    print(time.time()-start)
    
  • 相关阅读:
    C#中ref和out的原理
    C#托管堆和垃圾回收(GC)
    C#类成员初始化顺序
    HTTP认证之摘要认证——Digest(二)
    HTTP认证之摘要认证——Digest(一)
    设计模式之建造者模式——Builder
    Shader专题:卡通着色(一)控制颜色的艺术
    小班同学学习经历分享(一)游戏程序员成长札记
    UniRx精讲(二):独立的 Update &UniRx 的基本语法格式
    UniRx精讲(一):UniRx简介&定时功能实现
  • 原文地址:https://www.cnblogs.com/sunqim16/p/6831118.html
Copyright © 2020-2023  润新知