zoukankan      html  css  js  c++  java
  • 单线程+多任务异步协程

    1.基础概念

    1.协程

       - 在函数(特殊的函数)定义的时候,如果使用了async修饰的话,则改变函数调用后返回一个协程对象,并且函数内部的实现语句不会被立即执行。

    2.任务对象

      - 任务对象就是对协程对象的进一步封装,任务对象==高级的协程对象==特殊的函数

      - 任务对象必须要注册到事件循环对象中

      - 给任务对象绑定回调函数:爬虫的数据解析中

    3.事件循环

      - 当作是一个容器,容器中必须存放任务对象

      - 当启动事件循环对象后,则事件循环对象会对其内部存储任务对象进行一步的执行

    4.aiohttp

      - 支持异步网络请求的模块

    协程

    import asyncio
    
    
    def callback(task):  # 作为任务对象的回调函数
        print('i am callback and ', task.result())  # task.result是用来接收特殊函数的返回值
    
    
    async def test():
        print("i am test")
        return "123"
    
    
    c = test()
    # 封装了一个任务对象
    task = asyncio.ensure_future(c)
    task.add_done_callback(callback)
    # 创建一个事件循环的对象
    loop = asyncio.get_event_loop()
    loop.run_until_complete(task)
    
    # 执行结果
    i am test
    i am callback and  123

    多任务

    import time
    import asyncio
    
    start = time.time()
    
    # 在特殊函数内部的实现中不可以出现不支持异步的模块代码
    async def get_request(url):
        await asyncio.sleep(2)
        print("下载成功:", url)
    
    
    urls = [
        'www.1.com',
        'www.2.com',
    ]
    
    tasks = []
    for url in urls:
        c = get_request(url)
        task = asyncio.ensure_future(c)
        tasks.append(task)
    loop = asyncio.get_event_loop()
    # 注意:挂起操作需要手动处理
    loop.run_until_complete(asyncio.wait(tasks))
    print(time.time() - start)
    
    # 执行结果:
    下载成功: www.1.com
    下载成功: www.2.com
    2.0021142959594727

    在爬虫中的应用

    # flask_server.py
    from flask import Flask
    import time
    app = Flask(__name__)
    @app.route('/bobo')
    def index_bobo():
        time.sleep(2)
        return 'Hello bobo'
    
    @app.route('/jay')
    def index_jay():
        time.sleep(2)
        return 'Hello jay'
    
    if __name__ == '__main__':
        app.run(threaded=True)
    
    
    # 在爬虫中的应用.py
    import time
    import asyncio
    import aiohttp
    
    
    start = time.time()
    urls = [
        'http://127.0.0.1:5000/bobo',
        'http://127.0.0.1:5000/jay',
    ]
    
    
    async def get_request(url):
        async with aiohttp.ClientSession() as s:
            async with await s.get(url=url) as response:
                page_text = await response.text()
                # print(page_text)
        return page_text
    
    
    tasks = []
    for url in urls:
        c = get_request(url)
        task = asyncio.ensure_future(c)
        tasks.append(task)
    
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))
    print(time.time() - start)

     注意事项:

    • 在特殊函数内部不可以出现不支持异步模块的代码,否则会中断整个异步的效果!!!

    • iohttp支持异步请求的模块

    练习:

    # templates文件夹
    # test.html

    <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --> <title>Bootstrap 101 Template</title> <!-- Bootstrap --> <link href="bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <h1>你好,世界!</h1> <ul> <li>i am hero!!!</li> <li>i am superMan!!!</li> <li>i am Spider!!!</li> </ul> </body> </html>
    # flask_server.py

    from flask import Flask, render_template import time app = Flask(__name__) @app.route('/bobo') def index_bobo(): time.sleep(2) return render_template('test.html') @app.route('/jay') def index_jay(): time.sleep(2) return render_template('test.html') @app.route('/tom') def index_tom(): time.sleep(2) return render_template('test.html') if __name__ == '__main__': app.run(threaded=True) # crawler_practice.py

    import aiohttp import asyncio import time from lxml import etree start = time.time() urls = [ 'http://127.0.0.1:5000/bobo', 'http://127.0.0.1:5000/jay', 'http://127.0.0.1:5000/tom', ] # 特殊的函数:请求发送和响应数据的捕获 # 细节:在每一个with前加上async,在每一个阻塞操作的前边加上await async def get_request(url): async with aiohttp.ClientSession() as s: # s.get(url,headers,proxy="http://ip:port",params) async with await s.get(url) as response: page_text = await response.text() # read()返回的是byte类型的数据,text返回时的字符串类型的数据 return page_text # 回调函数(数据解析和数据持久化) def parse(task): page_text = task.result() tree = etree.HTML(page_text) parse_data = tree.xpath('//li/text()') print(parse_data) tasks = [] for url in urls: c = get_request(url) task = asyncio.ensure_future(c) task.add_done_callback(parse) tasks.append(task) loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks)) print(time.time()-start)

    待续

  • 相关阅读:
    单核时代,PHP之类多线程或者多进程的,是怎么处理并发的?是排队吗?
    高并发下的Node.js与负载均衡
    telnet 查看端口是否可访问
    同步与异步--
    函数式编程沉思录(草稿)
    面向状态机编程
    promise是有状态的moand
    异步链式编程—promise沉思录
    同步与异步
    网络编程释疑之:同步,异步,阻塞,非阻塞
  • 原文地址:https://www.cnblogs.com/zangyue/p/12201487.html
Copyright © 2011-2022 走看看