use tokio;
use tokio::time::{sleep, Duration};
use std::time::{UNIX_EPOCH, SystemTime};
use anyhow::{Result, Error};
#[tokio::main]
async fn main() -> Result<()> {
let task1 = tokio::spawn(async move{
loop{
sleep(Duration::from_millis(3)).await;
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)?
.as_millis();
if now as u128 % 9 == 0 {
//on >2 iterations here,
//if "task2" is running
//task2 should be terminated
//and the block below executed again
let task2 = tokio::spawn(async move{
println!("abc");
println!("cde");
println!("erg");
});
//how to join task 2 here
//so that task1 isn't blocked?
};
}; Ok::<(), Error>(())
});
tokio::join![task1];
Ok(())
}
[游樂場]
我需要運行 2 個或更多執行緒:
- [控制器執行緒]
loop{}控制我的程式流程的“計時器”執行緒, - [輔助執行緒] 對執行緒 1 提供的資料進行操作,單次執行或
loop{}
如果task1滿足條件,則資料已更改,我需要 abort task2。它不需要對舊資料進行操作,而是必須重新啟動。
我找到了諸如以下的解決方案:
task.abort();
但是,這可能會使我的代碼變得一團糟,但是我仍然在我的 Playground 示例中使用了它(無法弄清楚如何在沒有task2外部環境的情況下在那里實作它task1)。
理想情況下,我想以某種方式task2在主體外部宣告task1一個指定實體當前是否正在運行的句柄,并基于此進行控制。
盡管如此,在我開始輸入任何代碼之前,這已經是 3-4 級縮進,這讓我很困擾。
我的查詢:
- 是否有任何方法允許宣告生成可重用的塊,以便重新啟動不那么混亂?
- 是否有直接方法或其集合允許在程式架構中平滑重啟執行緒?
需要的是.abort() 從一開始就運行相同的執行緒。
uj5u.com熱心網友回復:
取消任務有兩種方式:
- 優雅地,通過類似
CancellationToken - 強行通過
.abort().
這是優雅取消的一種可能解決方案:
use anyhow::Result;
use tokio;
use tokio::time::{sleep, Duration};
use tokio_util::sync::CancellationToken;
async fn task2(value: u32, cancellation_token: CancellationToken) {
'outer: loop {
for msg in ["abc", "cde", "erg"] {
println!("task2: {} {}", msg, value);
tokio::select! {
_ = sleep(Duration::from_millis(500)) => {},
_ = cancellation_token.cancelled() => break 'outer,
};
}
}
}
async fn task1() -> Result<()> {
let mut value = 42;
let mut task2_cancellation_token = CancellationToken::new();
let mut task2_handle = tokio::spawn(task2(value, task2_cancellation_token.clone()));
let mut iteration = 0;
loop {
sleep(Duration::from_millis(300)).await;
iteration = 1;
if iteration % 9 == 0 {
println!("Cancelling task2 ...");
task2_cancellation_token.cancel();
println!("Waiting for task2 to finish ...");
task2_handle.await?;
println!("Updating value ...");
value = 1;
println!("Restarting task2 ...");
task2_cancellation_token = CancellationToken::new();
task2_handle = tokio::spawn(task2(value, task2_cancellation_token.clone()));
};
}
}
#[tokio::main]
async fn main() -> Result<()> {
task1().await
}
task2: abc 42
task2: cde 42
task2: erg 42
task2: abc 42
task2: cde 42
task2: erg 42
Cancelling task2 ...
Waiting for task2 to finish ...
Updating value ...
Restarting task2 ...
task2: abc 43
task2: cde 43
task2: erg 43
...
或者,這是通過以下方式強制執行的.abort():
use anyhow::Result;
use tokio;
use tokio::time::{sleep, Duration};
async fn task2(value: u32) {
loop {
for msg in ["abc", "cde", "erg"] {
println!("task2: {} {}", msg, value);
sleep(Duration::from_millis(500)).await;
}
}
}
async fn task1() -> Result<()> {
let mut value = 42;
let mut task2_handle = tokio::spawn(task2(value));
let mut iteration = 0;
loop {
sleep(Duration::from_millis(300)).await;
iteration = 1;
if iteration % 9 == 0 {
println!("Aborting task2 ...");
task2_handle.abort();
// Ignore return value, as it will most likely
// be a cancelled `JoinError`.
task2_handle.await.ok();
println!("Updating value ...");
value = 1;
println!("Restarting task2 ...");
task2_handle = tokio::spawn(task2(value));
};
}
}
#[tokio::main]
async fn main() -> Result<()> {
task1().await
}
task2: abc 42
task2: cde 42
task2: erg 42
task2: abc 42
task2: cde 42
task2: erg 42
Aborting task2 ...
Updating value ...
Restarting task2 ...
task2: abc 43
task2: cde 43
task2: erg 43
...
的優點和缺點
優雅取消更難正確實施。因此,如果您的任務允許,它abort()會更容易,并且在取消的任務中不需要任何額外的代碼。
也就是說,該任務無法對abort(). 如果您的任務只能在特定狀態下被取消,或者它必須在取消時運行一些關閉功能,那么優雅關閉是唯一的可能性。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/504220.html
