tokio::time::timeout后再次等待未来
Await for future again after tokio::time::timeout
背景:
我有一个进程使用 tokio::process
在 tokio 运行时生成带有句柄的 child 进程。
它还负责在杀死 child 后释放资源,根据文档 (std::process::Child, tokio::process::Child),这需要 parent 到 wait()
(或 await
in tokio)的过程。
并非所有进程对 SIGINT
或 SIGTERM
的行为都相同,所以我想在发送 [=19= 之前给 child 一些时间来结束].
所需的解决方案:
pub async fn kill(self) {
// Close input
std::mem::drop(self.stdin);
// Send gracefull signal
let pid = nix::unistd::Pid::from_raw(self.process.id() as nix::libc::pid_t);
nix::sys::signal::kill(pid, nix::sys::signal::SIGINT);
// Give the process time to die gracefully
if let Err(_) = tokio::time::timeout(std::time::Duration::from_secs(2), self.process).await
{
// Kill forcefully
nix::sys::signal::kill(pid, nix::sys::signal::SIGKILL);
self.process.await;
}
}
然而给出这个错误:
error[E0382]: use of moved value: `self.process`
--> src/bin/multi/process.rs:46:13
|
42 | if let Err(_) = tokio::time::timeout(std::time::Duration::from_secs(2), self.process).await
| ------------ value moved here
...
46 | self.process.await;
| ^^^^^^^^^^^^ value used here after move
|
= note: move occurs because `self.process` has type `tokio::process::Child`, which does not implement the `Copy` trait
如果我遵守并删除 self.process.await
,我会看到 child 进程仍在 ps
中占用资源。
问题:
我如何 await
一段时间并执行操作,如果时间过期又如何 await
?
注:
我通过设置一个总是在两秒后发送 SIGKILL
并在底部有一个 self.process.await
的 tokio 计时器解决了我的直接问题。但是这个解决方案是不可取的,因为当计时器为 运行.
时,另一个进程可能会在同一个 PID 中产生
编辑:
添加一个 minimal, reproducible example (playground)
async fn delay() {
for _ in 0..6 {
tokio::time::delay_for(std::time::Duration::from_millis(500)).await;
println!("Ping!");
}
}
async fn runner() {
let delayer = delay();
if let Err(_) = tokio::time::timeout(std::time::Duration::from_secs(2), delayer).await {
println!("Taking more than two seconds");
delayer.await;
}
}
您需要传递可变引用。但是,您首先需要固定未来,以便其可变引用实现 Future。 pin_mut re-exported from the futures crate 是这方面的好帮手:
use futures::pin_mut;
async fn delay() {
for _ in 0..6 {
tokio::time::delay_for(std::time::Duration::from_millis(500)).await;
println!("Ping!");
}
}
async fn runner() {
let delayer = delay();
pin_mut!(delayer);
if let Err(_) = tokio::time::timeout(std::time::Duration::from_secs(2), &mut delayer).await {
println!("Taking more than two seconds");
delayer.await;
}
}
背景:
我有一个进程使用 tokio::process
在 tokio 运行时生成带有句柄的 child 进程。
它还负责在杀死 child 后释放资源,根据文档 (std::process::Child, tokio::process::Child),这需要 parent 到 wait()
(或 await
in tokio)的过程。
并非所有进程对 SIGINT
或 SIGTERM
的行为都相同,所以我想在发送 [=19= 之前给 child 一些时间来结束].
所需的解决方案:
pub async fn kill(self) {
// Close input
std::mem::drop(self.stdin);
// Send gracefull signal
let pid = nix::unistd::Pid::from_raw(self.process.id() as nix::libc::pid_t);
nix::sys::signal::kill(pid, nix::sys::signal::SIGINT);
// Give the process time to die gracefully
if let Err(_) = tokio::time::timeout(std::time::Duration::from_secs(2), self.process).await
{
// Kill forcefully
nix::sys::signal::kill(pid, nix::sys::signal::SIGKILL);
self.process.await;
}
}
然而给出这个错误:
error[E0382]: use of moved value: `self.process`
--> src/bin/multi/process.rs:46:13
|
42 | if let Err(_) = tokio::time::timeout(std::time::Duration::from_secs(2), self.process).await
| ------------ value moved here
...
46 | self.process.await;
| ^^^^^^^^^^^^ value used here after move
|
= note: move occurs because `self.process` has type `tokio::process::Child`, which does not implement the `Copy` trait
如果我遵守并删除 self.process.await
,我会看到 child 进程仍在 ps
中占用资源。
问题:
我如何 await
一段时间并执行操作,如果时间过期又如何 await
?
注:
我通过设置一个总是在两秒后发送 SIGKILL
并在底部有一个 self.process.await
的 tokio 计时器解决了我的直接问题。但是这个解决方案是不可取的,因为当计时器为 运行.
编辑:
添加一个 minimal, reproducible example (playground)
async fn delay() {
for _ in 0..6 {
tokio::time::delay_for(std::time::Duration::from_millis(500)).await;
println!("Ping!");
}
}
async fn runner() {
let delayer = delay();
if let Err(_) = tokio::time::timeout(std::time::Duration::from_secs(2), delayer).await {
println!("Taking more than two seconds");
delayer.await;
}
}
您需要传递可变引用。但是,您首先需要固定未来,以便其可变引用实现 Future。 pin_mut re-exported from the futures crate 是这方面的好帮手:
use futures::pin_mut;
async fn delay() {
for _ in 0..6 {
tokio::time::delay_for(std::time::Duration::from_millis(500)).await;
println!("Ping!");
}
}
async fn runner() {
let delayer = delay();
pin_mut!(delayer);
if let Err(_) = tokio::time::timeout(std::time::Duration::from_secs(2), &mut delayer).await {
println!("Taking more than two seconds");
delayer.await;
}
}