zoukankan      html  css  js  c++  java
  • python学习之-- 协程

    协程(coroutine)
    也叫:微线程,是一种用户态的轻量级线程,就是在单线程下实现并发的效果。
    优点:
    1:无需线程上下文切换的开销。(就是函数之间来回切换)
    2:无需原子操作锁定及同步的开销。(如改一个变量就相当于一个原子操作,因为协程是在单线程内操作,属于串行,所以不需要锁的操作)
    3:方便切换控制流,简化编程模型。
    4:高并发+高扩展+低成本:一个CPU支持上万个协程都不是问题,所以很适合用于高并发处理。(因为它都在一个线程里处理)
    缺点:
    1:无法利用多核资源,协程的本质是个单线程,它不能同时将单个CPU上的多个核用上,协程需要和进程配合才能运行在多CPU上,一般用于CPU密集型
    2:进行阻塞操作会阻塞掉整个程序
    gevent (实现自动切换):是一个第三方库,可以通过gevent实现并发同步或异步编程,其中的主要模式是Greenlet,
    greenlet (实现手动切换)由gevent进行了封装

    举例:通过手动切换实现协程

     1 import gevent
     2 def fun1():
     3     print('输出函数1')
     4     gevent.sleep(2)
     5     print('函数1结束')
     6 def fun2():
     7     print('输出函数2')
     8     gevent.sleep(1)
     9     print('函数2结束')
    10 def fun3():
    11     print('输出函数3')
    12     gevent.sleep(0)
    13     print('函数3结束')
    14 gevent.joinall([gevent.spawn(fun1),gevent.spawn(fun2),gevent.spawn(fun3)])生成3个函数的自动切换
    View Code

    以上代码解释:对3个函数生成自动切换,先运行fun1函数,遇到sleep(2)是,执行等待2秒,然后直接切换到fun2函数,执行遇到sleep(1)时,执行
    等待1秒,继续切换到fun3函数,执行遇到sleep(0)时切换到fun1函数,发现sleep(2)未完成,又切换入fun2函数发现sleep(1)也没有执行完成,
    继续切换如fun3函数,这里sleep(0)不用等待,直接执行fun3的最后一个print,执行完成后,返回fun1函数的sleep,发现没有完成,又切入
    fun2函数,发现sleep(1)已完成,可以向下继续执行,执行完下面的语句后,最后返回fun1,这时fun1的sleep(2)已完成,继续执行fun1剩下的语句。

    举例:使用普通串行爬网页与使用协程的gevent进行爬网页对比用时

    import gevent,time
    from gevent import monkey
    from urllib import request
    monkey.patch_all() # gevent补丁,把当前的所有的IO操作都单独的坐上标记
    
    def web(url):
        print('开始爬网页%s' % url)
        res = request.urlopen(url)
        data = res.read()
        print('%d bytes received from %s' % (len(data),url))
    urls = [
        'https://web1/',
        'https://web2/',
        'https://web3/'
    ]
    # 串行模式执行
    time_start = time.time()
    for url in urls:
        web(url)
    print('同步cost',time.time()-time_start)
    # 协程并发模式执行
    async_time_start = time.time()
    gevent.joinall([
        gevent.spawn(web,'https://web1/'),
        gevent.spawn(web,'https://web2/'),
        gevent.spawn(web,'https://web3/')
    ])
    print('异步cost',time.time()-async_time_start)
    View Code

    举例:通过协程实现一个socket服务器端(客户端没啥变化不写了)

     1 import sys,socket,time,gevent
     2 from gevent import socket,monkey
     3 monkey.patch_all()
     4 
     5 def server():
     6     s = socket.socket()
     7     s.bind(('0.0.0.0',9999))
     8     s.listen(500)
     9     while True:
    10         cli,addr = s.accept()
    11        # 主要这里,将每个连进来的客户端对象交给协程并发处理
    12         gevent.spawn(handle_request,cli) 
    13 
    14 def handle_request(client):
    15     while True:
    16         try:
    17             data = client.recv(1024).decode()
    18             print(data)
    19             client.send(data.encode('utf-8'))
    20             if not data:
    21                 client.shutdown(socket.SHUT_WR)
    22         except Exception as e:
    23             print('err',e)
    24         finally:
    25             client.close()
    View Code
  • 相关阅读:
    网络与系统安全第四次作业
    2018-2019-1 20189203《linux内核原理与分析》第六周作业
    《网络攻防实践》第五周作业
    《网络攻防实践》第四周作业
    《网络攻防实践》第三周作业
    《网络攻防实践》第二周作业
    《网络攻防实践》第一周作业
    《Linux内核原理与分析》第九周作业
    《Linux内核原理与分析》第八周作业
    《Linux内核原理与分析》第七周作业
  • 原文地址:https://www.cnblogs.com/zy6103/p/7017234.html
Copyright © 2011-2022 走看看