我知道这个问题已经被问过很多次了,但我仍然不知道该怎么做(更多内容见下文)。
我正在尝试使用 std::thread::spawn
生成一个新线程,然后在其中运行一个异步循环。
我想运行的异步函数:
#[tokio::main]
pub async fn pull_tweets(pg_pool2: Arc<PgPool>, config2: Arc<Settings>) {
let mut scheduler = AsyncScheduler::new();
scheduler.every(10.seconds()).run(move || {
let arc_pool = pg_pool2.clone();
let arc_config = config2.clone();
async {
pull_from_main(arc_pool, arc_config).await;
}
});
tokio::spawn(async move {
loop {
scheduler.run_pending().await;
tokio::time::sleep(Duration::from_millis(100)).await;
}
});
}
产生一个线程来运行:
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let handle = thread::spawn(move || async {
pull_tweets(pg_pool2, config2).await;
});
}
错误:
error[E0277]: `()` is not a future
--> src/main.rs:89:9
|
89 | pull_tweets(pg_pool2, config2).await;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
|
= help: the trait `std::future::Future` is not implemented for `()`
= note: required by `poll`
The last comment here 在概括问题方面做得非常出色。似乎在某些时候需要实现 IntoFuture
的返回值,而我没有。我尝试将 Ok(())
添加到闭包和函数中,但没有成功。
`Result<(), ()>` is not a future
然后我注意到答案特别提到了 extension functions,我没有使用它。 This 还谈到了扩展功能。
其他一些 SO 答案:
所以似乎没有一个工作。有人可以帮助我理解 1) 为什么这里存在错误以及 2) 如何修复它?
注意 1:所有这些都可以通过将 std::thread::spawn
替换为 tokio::task::spawn_blocking
来轻松解决。但我有意按照 this article 尝试使用线程生成。
注意 2:关于我想要实现的目标的更广泛背景:我在异步循环中从 twitter 中提取 150,000 条推文。我想比较 2 个实现:在主运行时上运行与在单独线程上运行。后者是我挣扎的地方。
注意 3:在我看来,线程和异步任务是两种不同的原语,不能混用。即生成一个新线程不会影响任务的行为方式,生成一个新任务只会在现有线程上增加工作。如果这个世界观有误(以及我能读到的内容),请告诉我。
答案 0 :(得分:1)
#[tokio::main]
将您的函数转换为以下内容:
#[tokio::main]
pub fn pull_tweets(pg_pool2: Arc<PgPool>, config2: Arc<Settings>) {
let rt = tokio::Runtime::new();
rt.block_on(async {
let mut scheduler = AsyncScheduler::new();
// ...
});
}
请注意,它是一个 同步 函数,它生成一个新的运行时并运行内部 Future 直到完成。你没有await
它,它是一个单独的运行时,它有自己的专用线程池和调度程序:
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let handle = thread::spawn(move || {
pull_tweets(pg_pool2, config2);
});
}
请注意,您的原始示例在另一个方面是错误的:
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let handle = thread::spawn(move || async {
pull_tweets(pg_pool2, config2).await;
});
}
即使 pull_tweets
是一个异步函数,线程也不会做任何事情,因为你所做的只是在 async
块中创建另一个未来。创建的 future 不会被执行,因为 futures 懒惰(无论如何在该线程中没有执行器上下文)。
我会构建代码以直接在新线程中生成运行时,并从那里调用您想要的任何 async
函数:
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let handle = thread::spawn(move || {
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();
rt.block_on(async {
pull_tweets(pg_pool2, config2).await;
});
});
}
pub async fn pull_tweets(pg_pool2: Arc<PgPool>, config2: Arc<Settings>) {
// ...
}