六、异步协程


返回

6.1 gevent模块

  • gevent模块属于第三方模块

    from gevent import monkey;monkey.patch_all()
    
    import gevent
    import time
    
    def eat(name):
        print('%s eat 1' %name)
        gevent.sleep(2)  # gevent可以识别的io阻塞
        print('%s eat 2' %name)
    
    def play(name):
        print('%s play 1' %name)
        time.sleep(1)  # gevent不能直接识别,需要首行打补丁
        print('%s play 2' %name)
    
    
    g1=gevent.spawn(eat,'egon')
    g2=gevent.spawn(play,name='egon')
    
    # 或者gevent.joinall([g1,g2])
    g1.join()
    g2.join()  
    
    print('主')
    
    

6.2 asyncio模块

  • asyncio模块是python内置的模块

    import asyncio
    """
    直接调用
    """
    
    # 用async定义一个协程
    async def request(url):
        print('正在请求的url是', url)
        print('请求成功,', url)
        return url
    
    
    # 被async修饰的函数,调用之后返回一个 协程对象c
    c = request('www.baidu.com')
    
    # 1. 基于asyncio 创建一个 事件循环对象loop
    loop = asyncio.get_event_loop()
    
    # 2. 将 协程对象c 注册到 事件循环对象loop 中,然后启动loop
    loop.run_until_complete(c)
    
    
    import asyncio
    """
    通过task对象调用
    """
    
    # 用async定义一个协程
    async def request(url):
        print('正在请求的url是', url)
        print('请求成功,', url)
        return url
    
    
    # 被async修饰的函数,调用之后返回一个协程对象c
    c = request('www.baidu.com')
    
    # 1. 基于asyncio 创建一个 事件循环对象loop
    loop = asyncio.get_event_loop()
    
    # 2. 基于loop 创建一个 task对象
    task = loop.create_task(c)
    
    # 3. 将 task对象 注册到 事件循环对象loop 中,然后启动loop
    print(task)
    loop.run_until_complete(task)
    print(task)
    
    
    import asyncio
    """
    通过future对象调用
    """
    
    # 用async定义一个协程
    async def request(url):
        print('正在请求的url是', url)
        print('请求成功,', url)
        return url
    
    
    # 被async修饰的函数,调用之后返回一个协程对象c
    c = request('www.baidu.com')
    
    # 1. 基于asyncio 创建一个 事件循环对象loop
    loop = asyncio.get_event_loop()
    
    # 2. 基于asyncio 创建一个 future对象
    future = asyncio.ensure_future(c)
    
    # 3. 将 future对象 注册到 事件循环对象loop 中,然后启动loop
    print(future)
    loop.run_until_complete(future)
    print(future)
    
    
    import asyncio
    """
    调用回调函数
    """
    
    # 用async定义一个协程
    async def request(url):
        print('正在请求的url是', url)
        print('请求成功,', url)
        return url
      
      
    def callback_func(future):
        # result()返回的是任务对象中封装的协程对象对应函数的返回值
        print(future.result())
    
    
    # 被async修饰的函数,调用之后返回一个 协程对象c
    c = request('www.baidu.com')
    
    # 1. 基于asyncio 创建一个 事件循环对象loop
    loop = asyncio.get_event_loop()
    
    # 2. 基于asyncio 创建一个 future对象
    future = asyncio.ensure_future(c)
    
    # 3. 将 回调函数 绑定到 future对象 中
    future.add_done_callback(callback_func)
    
    # 4. 将 future对象 注册到 事件循环对象loop 中,然后启动loop
    loop.run_until_complete(future)
    
  • 示例一:模拟

    import asyncio
    
    
    # 用async定义一个协程
    async def request(url):
        print('正在下载', url)
        
        # 异步协程中出现同步模块相关的代码,无法实现异步。
        # time.sleep(2)
        
        # 在asyncio中遇到阻塞操作,用await进行手动挂起
        await asyncio.sleep(2)
        
        print('下载完毕', url)
    
    
    urls = [
        'www.baidu.com',
        'www.sogou.com',
        'www.goubanjia.com'
    ]
    
    # 任务列表:存放多个任务对象
    tasks = []
    for url in urls:
        c = request(url)
        task = asyncio.ensure_future(c)
        tasks.append(task)
    
    loop = asyncio.get_event_loop()
    # 将任务列表封装到wait中
    loop.run_until_complete(asyncio.wait(tasks))
    
    
  • 示例二:访问flask服务器

    import requests
    import asyncio
    import aiohttp
    
    
    async def get_page(url):
        async with aiohttp.ClientSession() as session:
            # get()、post():
            # headers,params/data,proxy='http://ip:port'
            async with await session.get(url=url) as response:
                # text()返回字符串形式的响应数据
                # read()返回的二进制形式的响应数据
                # json()返回的就是json对象
                # 注意:获取响应数据前,要用await进行手动挂起
                page_text = await response.text()
                print(page_text)
    
                
    urls = [
        'www.baidu.com',
        'www.sogou.com',
        'www.goubanjia.com'
    ]
    
    # 任务列表:存放多个任务对象
    tasks = []
    for url in urls:
        c = get_page(url)
        task = asyncio.ensure_future(c)
        tasks.append(task)
    
    loop = asyncio.get_event_loop()
    # 将任务列表封装到wait中
    loop.run_until_complete(asyncio.wait(tasks))
    
    
  • 示例三:访问网页

    import asyncio
    import aiohttp
    
    
    class GetArticle(object):
    
        def __init__(self, url, file):
            pass
    
        async def article2dict(self, menu_dict):
            pass
          
            # 异步协程:请求文章URL的text内容
            async with aiohttp.ClientSession() as session:
                try:
                    async with await session.get(url=article_url, headers=self.headers, timeout=5) as response:
                        # 使用gbk进行解码
                        article_text = await response.text(encoding='gbk')
                except Exception:
                    for i in range(1, 10):
                        print(f'请求 {article_url} 超时,第{i}次重复请求')
                        async with await session.get(url=article_url, headers=self.headers, timeout=5) as response:
                            article_text = await response.text(encoding='gbk')
                            print(f'第{i}次重复请求 {article_url} 成功')
                            # 访问成功,跳出循环
                            break
                            
            pass
    
        def run(self):
            """
            主函数
            :return:
            """
            pass
    
            # 任务列表:存放多个任务对象
            tasks = []
            for menu_dict in menu_list:
                c = self.article2dict(menu_dict)
                task = asyncio.ensure_future(c)
                tasks.append(task)
    
            loop = asyncio.get_event_loop()
    				# 将任务列表封装到wait中
            loop.run_until_complete(asyncio.wait(tasks))
            
            pass
    
    
返回