Python异步编程:asyncio库的使用说明,以及和multiprocessing 的性能对比(2分钟立马掌握)

关于同步和异步的理解:

当我执行一段程序时,不仅需要CPU处理,还需要硬盘、网络等IO操作。而事实是,CPU的速度远大于IO操作速度。

假设:此时有个程序的过程是,CPU处理--IO操作--CPU处理,进过三次操作才能完成。但是在进行IO操作时,程序就卡住了(因为太慢了)。

如果你写程序的逻辑是:先完成整个的------CPU处理--IO操作--CPU处理,才能进行下一个进程,那么,你的程序就是同步的。

如果你写程序的逻辑是:第一个线程先完成CPU处理,传递给IO操作,此时虽然卡住了,但是可以进行第二个线程再次从CPU处理开始。等第一个IO操作完成后,再交给CPU处理。第二个IO操作完成后,再交给CPU处理。这样你的程序就是异步的。

代码实现和对比

我们用几种不同的方式来运行---打印20个时间戳。

第一轮:同步的方式(我们刚学编程时,普遍的思维方式):即打印一个时间戳后停顿1秒。

 

import time
def hello():
    time.sleep(1)

def run():
    for i in range(10):
        hello()
        print('Hello World:%s' % time.time()) 

if __name__ == '__main__':
    run()

可以看到输出如下:确实是间隔一秒后输出结果。前后十个线程间隔为:9秒

第二轮:异步的方式,用到 multiprocessing 库:这也是个异步的库。

import time
from multiprocessing.pool import Pool

def hello():
    time.sleep(1)

def run(i):
    hello()
    print('Hello World:%s' % time.time())

if __name__ == '__main__':
    pool = Pool()  
    pool.map(run,[i for i in range(10)])

最终可以看到输出结果,前后十个进程间隔为:0.107秒

第三轮:异步的方式。使用asyncio库。

import time
import asyncio

# 这是定义异步函数,先记住写法即可
async def hello():
    asyncio.sleep(1)
    print('Hello World:%s' % time.time())

def run():
    for i in range(10):
        loop.run_until_complete(hello())  # 这是让这个事件一直处理下去,直到结束后再提交给下一步、进行该线程的剩余操作。

loop = asyncio.get_event_loop()  # 这是创建一个事件循环,可以理解为类中的,实例化的概念
if __name__ == '__main__':
    run()

最后的结果如下,前后十个线程的间隔为:0.001 秒

 

总结:

从以上测试可以看到同步和异步在性能上的差别还是很大的,如果程序更复杂,他们之间的差异会更大。

至于异步常用的库 multiprocessing 和asyncio 间,后者效率更高些,具体的差异细节,大家可以做更深入的测试进行调试。

基本的会用到的代码部分有:

async def get(i):
    print('1start',i)
    await asyncio.sleep(2)
    print('2start',i)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    tasks = []  
    for i in range(5):
        tasks.append(asyncio.ensure_future(get(i)))
    print(tasks)
    # tasks = [asyncio.ensure_future(get('1')),asyncio.ensure_future(get('2'))]
    loop.run_until_complete(asyncio.wait(tasks))

注意,有时,这个wait +do_someting()  会报错,如:

TypeError: object Response can't be used in 'await' expression 

这个错误的意思是 requests 返回的 Response 对象不能和 await 一起使用,await 后面的对象必须是如下格式之一

  1. 原生 coroutine 对象
  2. 一个由 types.coroutine() 修饰的生成器,这个生成器可以返回 coroutine 对象。
  3. 一个包含 __await 方法的对象返回的一个迭代器。

reqeusts 返回的 Response 不符合上面任一条件,因此就会报上面的错误了。

既然 await 后面的对象要是 coroutine 对象 ,那么将其包装在async 后面不就可以了吗?

async def delete_one(product):
    stat = time.time()
    await asyncio.sleep(3)
    await do_delete(product)
    print('这里用时',time.time()-stat)


async def do_delete(product):
    client = pymongo.MongoClient('mongodb://root:1111111@11111111111111:27017')
    db = client['traffic']
    db_next_day_data = db['next_day_data']
    return db_next_day_data.delete_one(product)


def delete_finish_data(result):
    tasks = []

    for i in result:
        departureAirport = i.get('departureAirport')
        arrivalAirport = i.get('arrivalAirport')
        flightDate = i.get('flightDate')
        flightNo = i.get('flightNo')
        product = {
            "flightNo": flightNo,
            "departureAirport": departureAirport,
            "arrivalAirport": arrivalAirport,
            "flightDate": flightDate,

        }
        tasks.append(asyncio.ensure_future(delete_one(product)))

    start = time.time()

    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))
    print('完成删除',time.time()-start)

 

 

 

 

更多的asyncio的使用场景,可以参考以下这篇说明:

http://www.sohu.com/a/302896961_571478

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值