我已经读了很多例子,博客文章,问题/答案关于asyncio
/async
/wait
在Python 3.5中,许多是复杂的,我发现最简单的可能是这个。
仍然使用ensure_future
,为了学习Python中的异步编程,我想看一个更小的示例,以及执行基本异步/等待示例所需的最小工具是什么。
问题:是否可以给出一个简单的示例,说明async
/await
是如何工作的,只使用这两个关键字code运行异步循环—其他Python代码,而不使用其他asyncio
函数?
例如:类似这样的东西:
import asyncio
async def async_foo():
print("async_foo started")
await asyncio.sleep(5)
print("async_foo done")
async def main():
asyncio.ensure_future(async_foo()) # fire and forget async_foo()
print('Do some actions 1')
await asyncio.sleep(5)
print('Do some actions 2')
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
但如果没有,则确保未来的
,并仍然演示wait/async是如何工作的。
Python3.7现在有了一个更简单的API(在我看来)和一个更简单的措辞(比“确保未来”更容易记住):您可以使用create\u task
,它返回一个任务对象(如果需要的话,以后可以使用它来取消任务)。
import asyncio
async def hello(i):
print(f"hello {i} started")
await asyncio.sleep(4)
print(f"hello {i} done")
async def main():
task1 = asyncio.create_task(hello(1)) # returns immediately, the task is created
await asyncio.sleep(3)
task2 = asyncio.create_task(hello(2))
await task1
await task2
asyncio.run(main()) # main loop
结果:
你好1开始了你好2开始了你好1结束了你好2结束了
如果需要获取这些异步函数的返回值,那么聚集
是有用的。下面的示例是受留档的启发,但不幸的是,文档没有显示什么聚集
是真正有用的:获取返回值!
import asyncio
async def factorial(n):
f = 1
for i in range(2, n + 1):
print(f"Computing factorial({n}), currently i={i}...")
await asyncio.sleep(1)
f *= i
return f
async def main():
L = await asyncio.gather(factorial(2), factorial(3), factorial(4))
print(L) # [2, 6, 24]
asyncio.run(main())
预期产出:
计算阶乘(2),当前i=2…
计算阶乘(3),当前i=2…
计算阶乘(4),当前i=2…
计算阶乘(3),当前i=3…
计算阶乘(4),当前i=4…
[2,6,24]
PS:即使您使用的是asyncio
,而不是trio
,后者的教程也有助于我学习Python异步编程。
有没有可能给出一个简单的例子来展示async
/wait
是如何工作的,只使用这两个关键字asyncio.get_event_loop()
run_until_complete
其他Python代码,但没有其他asyncio
函数?
这样就可以编写工作代码:
import asyncio
async def main():
print('done!')
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
但这样就不可能说明为什么需要asyncio。
顺便问一下,为什么需要asyncio
,而不仅仅是纯代码?答案是-asyncio
允许您在并行化I/O阻塞操作(如读取/写入网络)时获得性能优势。为了编写有用的示例,您需要使用这些操作的异步实现。
请阅读此答案以获得更详细的解释。
Upd:
好的,下面的示例使用asyncio.sleep
模拟I/O阻塞操作和asyncio.gather
演示如何同时运行多个阻塞操作:
import asyncio
async def io_related(name):
print(f'{name} started')
await asyncio.sleep(1)
print(f'{name} finished')
async def main():
await asyncio.gather(
io_related('first'),
io_related('second'),
) # 1s + 1s = over 1s
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
输出:
first started
second started
first finished
second finished
[Finished in 1.2s]
注意io_related
是如何开始的,仅仅一秒钟后,两个都完成了。
为了回答您的问题,我将为同一问题提供3种不同的解决方案。
案例1:普通python
import time
def sleep():
print(f'Time: {time.time() - start:.2f}')
time.sleep(1)
def sum(name, numbers):
total = 0
for number in numbers:
print(f'Task {name}: Computing {total}+{number}')
sleep()
total += number
print(f'Task {name}: Sum = {total}\n')
start = time.time()
tasks = [
sum("A", [1, 2]),
sum("B", [1, 2, 3]),
]
end = time.time()
print(f'Time: {end-start:.2f} sec')
输出:
Task A: Computing 0+1
Time: 0.00
Task A: Computing 1+2
Time: 1.00
Task A: Sum = 3
Task B: Computing 0+1
Time: 2.01
Task B: Computing 1+2
Time: 3.01
Task B: Computing 3+3
Time: 4.01
Task B: Sum = 6
Time: 5.02 sec
案例2:异步/等待做错了
import asyncio
import time
async def sleep():
print(f'Time: {time.time() - start:.2f}')
time.sleep(1)
async def sum(name, numbers):
total = 0
for number in numbers:
print(f'Task {name}: Computing {total}+{number}')
await sleep()
total += number
print(f'Task {name}: Sum = {total}\n')
start = time.time()
loop = asyncio.get_event_loop()
tasks = [
loop.create_task(sum("A", [1, 2])),
loop.create_task(sum("B", [1, 2, 3])),
]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
end = time.time()
print(f'Time: {end-start:.2f} sec')
输出:
Task A: Computing 0+1
Time: 0.00
Task A: Computing 1+2
Time: 1.00
Task A: Sum = 3
Task B: Computing 0+1
Time: 2.01
Task B: Computing 1+2
Time: 3.01
Task B: Computing 3+3
Time: 4.01
Task B: Sum = 6
Time: 5.01 sec
案例3:async/wait done right(与案例2相同,除了sleep
功能)
import asyncio
import time
async def sleep():
print(f'Time: {time.time() - start:.2f}')
await asyncio.sleep(1)
async def sum(name, numbers):
total = 0
for number in numbers:
print(f'Task {name}: Computing {total}+{number}')
await sleep()
total += number
print(f'Task {name}: Sum = {total}\n')
start = time.time()
loop = asyncio.get_event_loop()
tasks = [
loop.create_task(sum("A", [1, 2])),
loop.create_task(sum("B", [1, 2, 3])),
]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
end = time.time()
print(f'Time: {end-start:.2f} sec')
输出:
Task A: Computing 0+1
Time: 0.00
Task B: Computing 0+1
Time: 0.00
Task A: Computing 1+2
Time: 1.00
Task B: Computing 1+2
Time: 1.00
Task A: Sum = 3
Task B: Computing 3+3
Time: 2.00
Task B: Sum = 6
Time: 3.01 sec
案例1
与案例2
给出相同的5秒
,而案例3
仅3秒
。因此,async/await done right
更快。
差异的原因在于sleep
功能的实现。
# case 1
def sleep():
print(f'Time: {time.time() - start:.2f}')
time.sleep(1)
# case 2
async def sleep():
print(f'Time: {time.time() - start:.2f}')
time.sleep(1)
# case 3
async def sleep():
print(f'Time: {time.time() - start:.2f}')
await asyncio.sleep(1)
sleep
在case1
和case2
中的功能是“相同的”。他们在不允许他人使用资源的情况下“睡觉”。而案例3
允许在资源处于Hibernate状态时访问资源。
在案例2中
我们将异步
添加到了正常函数中。但是,事件循环将不中断地运行它。为什么?因为我们没有告诉在哪里允许循环中断函数来运行另一个任务。
在案例3
中,我们告诉事件循环在何处中断函数以运行另一个任务。具体在哪里?
# case 3
async def sleep():
print(f'Time: {time.time() - start:.2f}')
await asyncio.sleep(1) # <-- Right here!
更多关于这一点,请阅读这里
更新02/五月/2020
考虑阅读
我试图在react/electron项目中使用async/await,但它不起作用。我想要的是获取docker容器状态列表。但是安慰。日志(列表)返回未定义的。 有人能帮我吗?:)
问题内容: 我想删除一些mongodb集合,但这是一个异步任务。代码将是: 控制台显示: 确保删除所有收藏集后将被打印的最简单方法是什么?任何第三方都可以用来简化代码。 问题答案: 我看到您正在使用,因此您正在谈论服务器端JavaScript。在这种情况下,我建议您查看异步模块并使用。您会发现此模块确实有用-它是为解决您所遇到的问题而开发的。您的代码可能如下所示
我遇到了一些使用c#的/关键字进行异步编程的最佳实践(我是c# 5.0的新手)。 给出的建议之一如下: 稳定性:了解您的同步上下文 ...一些同步上下文是不可重入的和单线程的。这意味着在给定时间只能在上下文中执行一个工作单元。这方面的一个例子是Windows UI线程或ASP.NET请求上下文。在这些单线程同步上下文中,很容易死锁。如果您从单线程上下文中生成一个任务,然后在上下文中等待该任务,您的
我正在尝试将数据库调用移出控制器,以清理并使其可测试。当它们在控制器中时,一切都会顺利进行。我将它们移出控制器,并添加了一个异步,以确保我们等待。否则,我将调用的中的函数。现在,一旦我使用async/await,控制器中的函数就会认为没有用户,因为它没有等待。 有几个关于异步等待的SO问题,但我没有找到一个解决我的问题。我确实验证了返回了我的用户,并添加了控制台日志来显示路径。 节点猫鼬异步等待似
任务或任务 我们也可以定义自己的可实现对象。对象应具有以下资格。 < li >它有一个GetAwaiter()方法(实例方法或扩展方法); < li >其GetAwaiter()方法返回一个Awaiter。在下列情况下,对象是一个标识符: < ul > < li >它实现INotifyCompletion或ICriticalNotifyCompletion接口; < li >它有一个IsCompl
我通读了Dart/flatter中的Async/Await/then,试图理解为什么aysnc函数中的Await不会等到完成后再继续。在我的UI中,有一个按钮调用一个异步方法来返回一个位置,该位置总是返回null,并且不等待函数完成。 该函数将调用推送到一个新的UI页面,该页面选择一个位置,并应返回一个结果。如何使该函数等待结果?我不是在使用异步吗?