• http


    ===协程是啥===

    简单来说,协程是一种基于线程之上,但又比线程更加轻量级的存在。对于系统内核来说,协程具有不可见的特性,所以这种由 程序员自己写程序来管理 的轻量级线程又常被称作 "用户空间线程"。

    ===协程比多线程好在哪===

    • 1. 线程的控制权在操作系统手中,而 协程的控制权完全掌握在用户自己手中,因此利用协程可以减少程序运行时的上下文切换,有效提高程序运行效率。
    • 2. 建立线程时,系统默认分配给线程的 栈 大小是 1 M,而协程更轻量,接近 1 K 。因此可以在相同的内存中开启更多的协程。
    • 3. 由于协程的本质不是多线程而是单线程,所以不需要多线程的锁机制。因为只有一个线程,也不存在同时写变量而引起的冲突。在协程中控制共享资源不需要加锁,只需要判断状态即可。所以协程的执行效率比多线程高很多,同时也有效避免了多线程中的竞争关系。

    适用场景:协程适用于被阻塞的,且需要大量并发的场景。

    不适用场景:协程不适用于存在大量计算的场景(因为协程的本质是单线程来回切换),如果遇到这种情况,还是应该使用其他手段去解决。

    相信用过 Python 切做过爬虫和接口测试的人都对 requests 库不陌生。requests 中实现的 http 请求是同步请求,但其实基于 http 请求 IO 阻塞的特性,非常适合用协程来实现 "异步" http 请求从而提升测试效率。 
    于是在 Github 经过了一番探索后,果不其然,最终寻找到了支持协程 "异步" 调用 http 的开源库: httpx。

    httpx 是一个几乎继承了所有 requests 的特性并且支持 "异步" http 请求的开源库。简单来说,可以认为 httpx 是强化版 requests。

    安装:pip install httpx

    单线程同步http请求耗时:

     1 import asyncio
     2 import httpx
     3 import threading
     4 import time
     5 
     6 def async_main(url, time):
     7     response = httpx.get(url).status_code # 请求状态码
     8     print(f'函数async_main当前线程{threading.current_thread()}: 请求次数{time} + 状态码 {response}')
     9 
    10 # 开始时间
    11 startTime = time.time()
    12 # 开始执行函数
    13 [async_main(url='https://www.baidu.com', time=i) for i in range(20)] # 测试20次
    14 endTime = time.time()
    15 
    16 print('总耗时为:', endTime-startTime)

    输出结果为:

     没有意外,单线程顺序同步请求。

    接下来是单线程“异步”请求:

     1 import asyncio
     2 import httpx
     3 import threading
     4 import time
     5 
     6 client = httpx.AsyncClient() # 异步请求
     7 
     8 # 主函数
     9 async def async_main(url, time):
    10     response = await client.get(url) # 调用client请求url
    11     status_code = response.status_code # 请求状态码
    12     print(f'函数async_main当前线程{threading.current_thread()}: 请求次数{time} + 状态码{status_code}')
    13 
    14 loop = asyncio.get_event_loop() # 获取事件
    15 # print(loop) # <ProactorEventLoop running=False closed=False debug=False>
    16 
    17 # 建立任务
    18 tasks = [async_main(url='https://www.baidu.com', time=i) for i in range(20)] # 还是搞20次
    19 startTime = time.time() # 开始时间
    20 loop.run_until_complete(asyncio.wait(tasks)) # 异步事件一直运行,直至tasks里的任务完成
    21 endTime = time.time() # 结束事件
    22 loop.close() # 关闭时间循环
    23 print('总耗时为: ', endTime-startTime)

    输出结果如下:

     

    异步快还是快的,总耗时将近是同步的10分1。可以看到顺序虽然是乱的16,18,1... ,这是因为程序在协程间不停切换, 但是主线程并没有切换 ,协程本质还是单线程 。

  • 相关阅读:
    二分查找
    转:归并排序
    C++ STL stack和queue
    spring-第十九篇AOP面向切面编程之增强处理的优先级
    spring-第十八篇之spring AOP基于XML配置文件的管理方式
    spring-第十七篇之spring AOP基于注解的零配置方式
    spring-第十一篇之SpEL表达式
    spring-第八篇之容器中的bean的生命周期
    spring-第七篇之深入理解容器中的bean
    spring-第二篇ApplicationContext国际化及事件机制
  • 原文地址:https://www.cnblogs.com/mafu/p/15540223.html
Copyright © 2020-2023  润新知