【python 异步IO】Python async/await 介绍

Python3.5增加了内置的async和await关键字。让我们用几个小例子来展示一下这两个关键字如何使用。

如果你不明白什么是“异步编程”,你可以简单地理解它为“在单个进程中同时处理多个任务的一种方法”。我们通常使用的进程经常花费大量的时间等待IO操作的完成。这种IO操作包括客户端请求网络、读取文件、查询数据库等等….同步程序一般是等待IO操作完成后再进行下一个任务,而异步程序则可以在IO操作期间去处理下一个任务。

这和你准备早餐的步骤有点相似。你煮了咖啡和茶,但是你不会待在那里等咖啡和茶煮好,而是直接去做饭或者烤面包了。你会并行地做多件事,当其中某项完成时,你会得到一个通知(可能是你的咖啡机或者电饭煲会叫)。这样,虽然你是一个进程,但是你能够更高效地同时完成很多工作。

我们下面看一个简单的例子,这里我们用asyncio.sleep模拟耗时的IO操作,并用asyncio.wait让它们并行运行.

python 3.4

import asyncio

@asyncio.coroutine
def slow_operation(n):
    yield from asyncio.sleep(1)
    print("Slow operation {} complete".format(n))


@asyncio.coroutine
def main():
    yield from asyncio.wait([
        slow_operation(1),
        slow_operation(2),
        slow_operation(3),
    ])


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

以下python 3.5

import asyncio

async def slow_operation(n):
    await asyncio.sleep(1)
    print("Slow operation {} complete".format(n))


async def main():
    await asyncio.wait([
        slow_operation(1),
        slow_operation(2),
        slow_operation(3),
    ])


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

新的async和await关键字清楚地表明我们在写的是一个异步函数,而不是普通的生成器。

已标记关键词 清除标记
关于python asyncawait的使用,我已经尝试了一个星期了 ``` async def updateAdventureCnt(): conn = pymysql.connect(host=HOST,db = DB ,user=USER, passwd=PAWD, port=0, charset="utf8", init_command="SET NAMES utf8") cur = conn.cursor() print("database to connect successfully.") sql = ''' select char_oid,expedition_point,cur_adventure_cnt FROM char_data ''' cur.execute(sql) # 执行sql语句 conn.commit() # 提交到数据库执行 rows = cur.fetchall() for row in rows: expediton_point = row[1] if expediton_point > 0: char_oid = row[0] cur_adventure_cnt = row[2] + expediton_point * 3 UpdateSql = ''' UPDATE char_data SET cur_adventure_cnt=%d where char_oid = %d ''' % (cur_adventure_cnt, char_oid) cur.execute(UpdateSql) conn.commit() # return 'update ok' # cur.close() # 关闭数据库 # conn.close() ``` 上图代码是简单的同步刷mysql数据可的代码,代码运行没有问题,使用async声明此函数为协程函数。 ``` async def test1(): a = time.time() r = await updateAdventureCnt() print(time.time()-a) print('线程是',threading.currentThread()) print(r) ``` 这里又加装了一层协程函数,是为了打印,方便我看出来是否是异步运行 ``` loop = asyncio.get_event_loop() tasks = [test1(),test1()] loop.run_until_complete(asyncio.wait(tasks)) loop.close() ``` 这里是实际运行,我对此操作数据库的函数运行了两次 ``` database to connect successfully. 3.461343288421631 线程是 <_MainThread(MainThread, started 3728)> None database to connect successfully. 3.5280568599700928 线程是 <_MainThread(MainThread, started 3728)> None ``` 这里是实际运行结果 通过以上,明显可以看出来,我仍然是在同步运行,并没有起到异步的效果,白白声明了几个协程函数,和使用AWAIT等待结果。 而我的本意是希望在我操作数据库,在阻塞的时候(例如提交和等待结果),跳过这个阻塞,去运行另一个操作数据库的任务,直到第一个任务返回结果,继续运行,这应该才是异步的操作。 我想知道我上面的代码,究竟是什么地方出现了问题,导致我不能达到异步的效果, 而我自己的猜测, 第一个原因我的数据库操作都是阻塞运行的,所以导致代码一直从上往下运行了两遍。但是我能力有限,没办法使用await或者其他办法来使这些IO非阻塞,并等待结果返回。 如果是这个原因导致程序无法运行的,我希望有人能帮我解决,或者书写一个简单的示例,这个示例我不希望是使用了各种异步库的,因为这些异步库本身已经进行了协程的封装,他们前面是可以合理使用await使其非阻塞和等待结果的,这个我是知道的,而我疑惑的是,如果我自己要书写一个例如asyncio.sleep(10) 一样的函数,使其可以await非阻塞,有了结果会回调,会很麻烦吗。 第二个原因 loop.run_until_complete(asyncio.wait(tasks)) 是否我运行的方式不正确?
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页