如何在mojo中实现异步代码(使用
async
等)?
在Changelog中,我找到以下示例(略有调整):
async fn add_three(a: Int, b: Int, c: Int) -> Int:
return a + b + c
async fn call_it():
var task = add_three(1, 2, 3)
print(await task)
这给了我以下编译器错误:
test_async.mojo:39:17: error: 'Coroutine[Int, {}]' is not copyable because it has no '__copyinit__'
print(await task)
^~~~
我不明白这个错误,因为我认为
Coroutine
是可以寄存器通过的(如源代码中所示)。有效的是
async fn add_three(a: Int, b: Int, c: Int) -> Int:
return a + b + c
async fn call_it():
var task = await add_three(1, 2, 3)
print(task)
但是,如果我总是将
await
放在右侧,我将永远无法异步执行代码,因为我总是在等待该行完成。我做错了什么/我的误解在哪里? (或者这只是一个错误?)
在变更日志中,它还表示任务可以在完成后“恢复”(请参阅此处)。 “恢复”是什么意思以及我该怎么做?
我正在开发当前的夜间构建版本:mojo 2024.7.2005 (96a1562c)。
注意:我也在mojo的问答页面发布了这个问题,但到目前为止还没有看到任何反应。如果我在那里收到答案,我会更新这篇文章。
问题在于协程(
async
函数的结果)不可复制;即它只能存在一次。这是有道理的,因为副本需要指向相同的异步任务,这意味着副本并不是“真正”相互独立。
解决方案是调用 move init,这可以通过此处的
^
运算符来完成。该运算符确保协程变量的值之后不再使用并转移所有权。
async fn call_it():
var task = add_three(1, 2, 3)
print(await task^)
这就像魅力一样。同样,我们也可以将最终结果移动到另一个“经典”变量(即不是协程):
async fn call_it():
var task = add_three(1, 2, 3)
var other = await task^
print(other)