前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python协程--asyncio模块

python协程--asyncio模块

作者头像
py3study
发布2020-01-21 13:17:47
8000
发布2020-01-21 13:17:47
举报
文章被收录于专栏:python3python3

在高并发的场景下,python提供了一个多线程的模块threading,但似乎这个模块并不近人如意,原因在于cpython本身的全局解析锁(GIL)问题,在一段时间片内实际上的执行是单线程的。同时还存在着资源争夺的问题。python3.4之后引入了基于生成器对象的协程概念。也就是asyncio模块。除了asyncio模块,python在高并发这一问题还提出了另外一些解决方案,例如tornado和gevent都实现了类似的功能。由此,在方案选择上提供了更多的可能性。以下是threading模块和asyncio模块对比测试实验。asyncio模块的具体使用,我希望自己在另一篇文章再写。

一、threading模块

threading模块中的thread线程 密集 运算争夺变量测试

代码:

代码语言:javascript
复制
#多线程共有数据的争夺检测
from threading import Thread,currentThread
import time
def do_something(x):
    global a
    time.sleep(x)
    for b in range(1,51):   #计算从1+...+50
        a+=b
    print(currentThread(),":",a)

a = 0
threads = []

for i  in  range(1,20000):                        #为了突出效果,线程量开到接近20000
   thread = Thread(target=do_something,args=(1,))
   threads.append(thread)

for thread in threads:
    thread.start()
代码语言:javascript
复制
截取部分结果:
<Thread(Thread-19972, started 34476)> : 25408200
<Thread(Thread-19971, started 34548)> : 25409475
<Thread(Thread-19991, started 12644)> : 25410750
<Thread(Thread-19990, started 34580)> : 25412025
<Thread(Thread-19989, started 34404)> : 25413300
<Thread(Thread-19986, started 34044)> : 25414575
<Thread(Thread-19983, started 34648)> : 25415850
<Thread(Thread-19982, started 34128)> : 25417125

运行时间:
6.9629926681518555
6.8796374797821045
7.3379065990448
平均运行时间:7.0秒

由结果可以看出,多线程在密集型运算的(占用大量CPU运算单元)情况下,会出现前后同一变量的数据不一致的情况。也就是所谓的“竞态问题”。

二、asyncio模块

asyncio模块 密集运算测试(线程安全!不存在争夺资源问题),所以协程在密集运算和IO并发上都有很强的支持。

代码:

代码语言:javascript
复制
#密集运算测试
import asyncio

a = 0
tasks = []
num = 0
async def do_something(x):
    global a
    global num
    #num += 1         # 思路3:num自增的位置(在阻塞前/后)不同会产生不同的结果
    await asyncio.sleep(x)
    for b in range(1,51):   #计算从1+...+50
        a+=b
    num += 1            #思路1
print("this is coroutetime",":",num,a)    #思路1,思路3
print("this is coroutetime",":",x,a)       #思路2

for i in range(1,20000):             #即使睡眠的时间很短,运算量大都不会产生资源争夺
coroutine = do_something(1)                   #思路1
# coroutine = do_something(i*0.01)              #思路2
# coroutine = do_something(3//i)                #思路3
    tasks.append(asyncio.ensure_future(coroutine))

loop = asyncio.get_event_loop()      #创建事件循环
loop.run_until_complete(asyncio.wait(tasks))     #将协程塞进事件循环中

代码实现思路:

(1)思路1:每一个协程的睡眠时间相同,也就是说几乎是同时在运行密集型计算,并用num自增计算作为协程的代号。

(2)思路2:为了区别开不同协程的占据CPU的运行时间片,我对睡眠时间进行了一个乘法运算,协程代号越大的协程睡眠时间越长,并用时间作为协程代号的记录。

(3)思路3:这次我将睡眠时间作一个调整,用除法运算,也就是说,协程代号越大的,睡眠时间越短,不过这次协程代号用num来记录,并且放在了睡眠(阻塞)之前。

摘取前几个数据

代码语言:javascript
复制
思路1:当设定的睡眠时间(阻塞时间)相同时,结果的打印几乎是同时出现
this is coroutetime : 1 1275
this is coroutetime : 2 2550
this is coroutetime : 3 3825
this is coroutetime : 4 5100
this is coroutetime : 5 6375
this is coroutetime : 6 7650
this is coroutetime : 7 8925
this is coroutetime : 8 10200


思路1运行时间:
3.0337979793548584
3.159485340118408
3.095968008041382
平均运行时间3.08秒
代码语言:javascript
复制
思路2:当设定的睡眠时间(阻塞时间)不同,协程代号就是睡眠的时间
this is coroutetime : 0.01 1275
this is coroutetime : 0.02 2550
this is coroutetime : 0.03 3825
this is coroutetime : 0.04 5100
this is coroutetime : 0.05 6375
this is coroutetime : 0.06 7650
this is coroutetime : 0.07 8925
this is coroutetime : 0.08 10200

由上面两组数据可以看出,无论协程是同时进行还是分时间段进行,都是严格按照顺序来执行的。思路2的结果很符合我们的认知常识,那么思路1的结果是怎么得来的呢?原因在于,多并发(此处的密集型运算用于模拟一系列的并发内部操作)情况下,阻塞的协程会暂时被搁置,切换到另外的协程。可以将协程的运行理解为一个队列,当大量协程来临的时候,无法一次性执行,于是放进一个类似队列的容器(WeakSet),并且不断检测这个队列中哪一个协程是处于非阻塞状态的,去调用这个协程的资源并运行。队列中的每一个元素间是互不干扰的。于是,就出现了以上的结果----有序的协程运行。

代码语言:javascript
复制
思路3:再看下面一组数据
this is coroutetime : 1999 1275
this is coroutetime : 1999 2550
this is coroutetime : 1999 3825
this is coroutetime : 1999 5100
this is coroutetime : 1999 6375
this is coroutetime : 1999 7650
this is coroutetime : 1999 8925
this is coroutetime : 1999 10200

为什么所有的协程号都一样

因为最大协程号,睡眠时间最短,所以它先执行输出,而协程号是累加的,所以后面执行的线程都会以最大的协程号作为标记。由此进一步看出

三、性能对比

完成时间对比:

threading:平均运行时间:7.0秒

anyncio:平均运行时间3.08秒

由上面的多线程模块threading和协程模块asyncio的对比可以看出,ansyncio的完成时间是threading的一半左右。由此,asyncio在高并发的情况下具有比较大的优势,并且在资源的保护上也做得比threading要好。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-04-23 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档