• python协程和任务


    协程概念引入

    ​ 协程是我要重点去讲解的一个知识点. 它能够更加高效的利用CPU.

    ​ 其实, 我们能够高效的利用多线程来完成爬虫其实已经很6了. 但是, 从某种角度讲, 线程的执行效率真的就无敌了么? 我们真的充分的利用CPU资源了么? 非也~ 比如, 我们来看下面这个例子.

    我们单独的用一个线程来完成某一个操作. 看看它的效率是否真的能把CPU完全利用起来.

    import time
    
    def func():
        print("我爱黎明")
        time.sleep(3)
        print("我真的爱黎明")
       
    func()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    ​ 各位请看. 在该程序中, 我们的func()实际在执行的时候至少需要3秒的时间来完成操作. 中间的三秒钟需要让我当前的线程处于阻塞状态. 阻塞状态的线程 CPU是不会来执行你的. 那么此时cpu很可能会切换到其他程序上去执行. 此时, 对于你来说, CPU其实并没有为你工作(在这三秒内), 那么我们能不能通过某种手段, 让CPU一直为我而工作. 尽量的不要去管其他人.

    ​ 我们要知道CPU一般抛开执行周期不谈, 如果一个线程遇到了IO操作, CPU就会自动的切换到其他线程进行执行. 那么, 如果我想办法让我的线程遇到了IO操作就挂起, 留下的都是运算操作. 那CPU是不是就会长时间的来照顾我~.

    ​ 以此为目的, 伟大的程序员就发明了一个新的执行过程. 当线程中遇到了IO操作的时候, 将线程中的任务进行切换, 切换成非 IO操作. 等原来的IO执行完了. 再恢复回原来的任务中.

    async def func():
        print("我是协程")
    if __name__ == '__main__':
        # print(func())  # 注意, 此时拿到的是一个协程对象, 和生成器差不多.该函数默认是不会这样执行的
    
        coroutine = func()
        asyncio.run(coroutine)  # 用asyncio的run来执行协程.
        # lop = asyncio.get_event_loop()
        # lop.run_until_complete(coroutine)   # 这两句顶上面一句
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    async def main():
        print("start")
        # # 添加协程任务
        # t1 = asyncio.create_task(func1())
        # t2 = asyncio.create_task(func2())
        # t3 = asyncio.create_task(func3())
        #
        # ret1 = await t1
        # ret2 = await t2
        # ret3 = await t3
    
        tasks = [
            asyncio.create_task(func1()),
            asyncio.create_task(func2()),
            asyncio.create_task(func3())
        ]
        # 一次性把所有任务都执行
        done, pedding = await asyncio.wait(tasks)
        
        print("end")
    
    if __name__ == '__main__':
        start = time.time()
        asyncio.run(main())
        print(time.time() - start)
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    异步请求(aiohttp)和同步请求(requests)的不同

    import aiohttp
    import asyncio
    import aiofiles
    
    
    async def download(url):
        try:
            name = url.split("/")[-1]
            # 创建session对象 -> 相当于requsts对象
            async with aiohttp.ClientSession() as session:
                # 发送请求, 这里和requests.get()几乎没区别, 除了代理换成了proxy
                async with session.get(url) as resp:
                    # 读取数据. 如果想要读取源代码. 直接resp.text()即可. 比原来多了个()
                    content = await resp.content.read()
                    # 写入文件, 用默认的open也OK. 用aiofiles能进一步提升效率
                    async with aiofiles.open(name, mode="wb") as f:
                        await f.write(content)
                        return "OK"
        except:
            print(123)
            return "NO"
    
    
    async def main():
        url_list = [
            "http://pic3.hn01.cn/wwl/upload/2021/06-30/omv2i40essl.jpg",
            "http://pic3.hn01.cn/wwl/upload/2021/06-30/kg3ccicvnqd.jpg",
            "http://pic3.hn01.cn/wwl/upload/2021/06-30/jhw5yhbtyaa.jpg",
            "http://pic3.hn01.cn/wwl/upload/2021/06-30/y1enehg1esu.jpg",
            "http://pic3.hn01.cn/wwl/upload/2021/06-28/2pshuolbhrg.jpg",
        ]
        tasks = []
    
        for url in url_list:
            # 创建任务
            task = asyncio.create_task(download(url))
            tasks.append(task)
    
        await asyncio.wait(tasks)
    
    
    if __name__ == '__main__':
        asyncio.run(main())
    
    
    async def factorial(name, number):
        f = 1
        for i in range(2, number + 1):
            print(f"Task {name}: Compute factorial({number}), currently i={i}...")
            await asyncio.sleep(1)
            f *= i
        print(f"Task {name}: factorial({number}) = {f}")
        return f
    
    async def main1():
        # Schedule three calls *concurrently*:
        L = await asyncio.gather(
            factorial("A", 2),
            factorial("B", 3),
            factorial("C", 4),
        )
        print(L)
    
    asyncio.run(main1())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
  • 相关阅读:
    目前很火的养猫微信小程序源码带流量主+搭建教程
    数据结构:队列
    初入数据库
    代码分割换行 处理元素中空白 white-space属性
    AI智能识别如何助力PDF,轻松实现文档处理?
    python打开浏览器并模拟搜索
    Python 无废话-基础知识函数详解
    【视频】机器学习交叉验证CV原理及R语言主成分PCA回归分析犯罪率|数据共享
    3D Slicer学习记录(0)--利用OpenIGTLink实现数据发送接收
    设计模式学习(五):原型模式
  • 原文地址:https://blog.csdn.net/jinying_51eqhappy/article/details/133639532