zoukankan      html  css  js  c++  java
  • 并发编程(线程)——定时器,协程,greenlet模块,gevent模块,单线程的套接字并发,asyncio模块

    一、定时器

    Timer的父类是Thread,所以定时器这里用的是线程

    # 多长时间之后执行一个任务
    from threading import Timer
    
    
    def task(name):
        print('我是大帅比--%s'%name)
    
    
    if __name__ == '__main__':
        # t = Timer(2, task,args=('lqz',))  # 本质是开了个线程,延迟一秒执行  Timer(秒数,函数,arges=一个元组)
        t = Timer(2, task,kwargs={'name':'lqz'})  # 本质是开了个线程,延迟一秒执行
        t.start()

    二、协程

    协程是为了实现单线程下的并发,属性线程下
    协程要解决的问题:保存状态+切换
    yield:生成器,只要函数中有yield关键字,这个函数就是生成器,通过yield可以实现保存状态+切换
    import time
    
    # 串行执行
    def func1():
        for i in range(100000000):
            i += 1
    
    
    def func2():
        for i in range(100000000):
            i += 1
    
    
    if __name__ == '__main__':
        ctime = time.time()
        func1()
        func2()
        print(time.time() - ctime)  # 7.03256796435
    
    
    # 通过yield,实现保存状态加切换(自定义的切换,并不是遇到io才切,所有它并不能节约时间)
    # 单纯的切换,不但不会提高效率,反而会讲低效率
    def func1():
        for i in range(100000000):
            i += 1
            yield
    
    
    def func2():
        g=func1() # 先执行一下func1
        for i in range(100000000):
            i += 1
            next(g) # 回到func1执行
    
    
    if __name__ == '__main__':
        ctime = time.time()
        func2()
        print(time.time() - ctime) #14.764776706695557
    
    
    
    # 协程并不是真是存在的某个东西,而是程序员臆想出来的
    # 程序员控制,不让自己的程序遇到io,看上去,就实现并发了
    
    '''
    优点如下:
    协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
    单线程内就可以实现并发的效果,最大限度地利用cpu
    
    缺点如下: 协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程 协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程
    总结协程特点: 必须在只有一个单线程里实现并发 修改共享数据不需加锁 用户程序里自己保存多个控制流的上下文栈(需要保存状态) 附加:一个协程遇到IO操作自动切换到其它协程(如何实现检测IO,yield、greenlet都无法实现,就用到了gevent模块(select机制))
    '''

    三、greenlet模块

    协程相关模块

    from greenlet import greenlet
    import time
    # 遇到io不会切,初级模块,gevent模块基于它写的,处理io切换
    def eat():
        print('我吃了一口')
        time.sleep(1)
        # p.switch()
        print('我又吃了一口')
        # p.switch()
    
    
    def play():
        print('我玩了一会')
        e.switch()
        print('我又玩了一会')
    
    
    if __name__ == '__main__':
        e = greenlet(eat)
        p = greenlet(play)
        e.switch()

    四、gevent模块

    协程相关模块

    # gevent基于greenlet写的,实现了遇见io自动切换
    import gevent
    import time
    
    def eat(name):
        print('%s 吃了一口' % name)
        gevent.sleep(1)  # io操作
        print('%s 又吃了一口' % name)
    
    
    def play(name):
        print('%s 玩了一会' % name)
        gevent.sleep(2)
        print('%s 又玩了一会' % name)
    
    
    if __name__ == '__main__':
        ctim = time.time()
        e = gevent.spawn(eat,'lqz')
        p = gevent.spawn(play,'lqz')
        e.join() # 等待e执行完成
        p.join()
        print('')
        print(time.time() - ctim)  #2.0165154933929443
    
        这个程序执行完成,最少需要多长时间 2s多一点
        ctim=time.time()
        eat('lqz')
        play('lqz')
        print(time.time()-ctim) # 3.0190377235412598

    gevent模块加上猴子补丁

    from gevent import monkey;monkey.patch_all()#这句话必须写
    import gevent
    import time
    
    def eat(name):
        print('%s 吃了一口' % name)
        time.sleep(1)  # io操作,被猴子补丁替换之后,gevent.sleep()
        print('%s 又吃了一口' % name)
    
    
    def play(name):
        print('%s 玩了一会' % name)
        time.sleep(2)
        print('%s 又玩了一会' % name)
    
    
    if __name__ == '__main__':
        ctim = time.time()
        e = gevent.spawn(eat,'lqz')
        p = gevent.spawn(play,'lqz')
        e.join() # 等待e执行完成
        p.join()
        print('')
        print(time.time() - ctim)  #2.0165154933929443

    五、单线程的套接字并发

    使用gevent实现单线程下的套接字并发效果

    六、asyncio模块

    3.4及其之前版本使用的asyncio模块

    import time
    import asyncio
    
    # 把普通函数变成协程函数
    # 3.4及其以前这么写,3.5开始就弃用了,3.5版本及其之后用了不报错但会提示已经启用
    @asyncio.coroutine
    def task():
        print('开始了')
        yield from asyncio.sleep(1)  #asyncio.sleep(1)模拟io
        print('结束了')
    
    
    loop=asyncio.get_event_loop()  # 获取一个时间循环对象#
    
    # 协程函数加括号,并不会真正的去执行,它需要提交给loop,让loop循环着去执行
    # 协程函数列表
    
    ctime=time.time()
    t=[task(),task()]
    loop.run_until_complete(asyncio.wait(t))
    loop.close()
    print(time.time()-ctime)

    现在使用的asyncio模块用法

    import time
    import asyncio
    from threading import current_thread
    # 表示我是协程函数,等同于3.5之前的装饰器
    async def task():
        print('开始了')
        print(current_thread().name)
        await asyncio.sleep(3)  # await等同于原来的yield from
        print('结束了')
    
    async def task2():
        print('开始了')
        print(current_thread().name)
        await asyncio.sleep(2)
        print('结束了')
    
    loop=asyncio.get_event_loop()
    
    ctime=time.time()
    t=[task(),task2()]
    loop.run_until_complete(asyncio.wait(t))
    loop.close()
    print(time.time()-ctime)

     ---40---

  • 相关阅读:
    leetcode--Search for a Range
    leetcode--Valid Palindrome
    leetcode--Validate Binary Search Tree
    leetcode--Count and Say
    leetcode--Partition List
    C语言atof()函数:将字符串转换为double(双精度浮点数)
    程序员与科学家的区别
    mingw编译rtmp库
    使用printf输出各种格式的字符串( 转载)
    c++使用stdint.h和inttypes.h
  • 原文地址:https://www.cnblogs.com/guojieying/p/13571829.html
Copyright © 2011-2022 走看看