簡體   English   中英

有一個 rust function 暫停執行並多次返回值而不丟失其堆棧

[英]Have a rust function pause execution and return a value multiple times in without losing its stack

我正在從事一個計算時間很長的項目,我將有數百個節點運行它,作為我實現的一部分,我有一個狀態處理程序對象/結構,它與 API 對話並獲取所需的信息,如 arguments,狀態處理程序然后調用主密集 function。

它為了密切關注計算密集型 function 我希望它以完成的百分比返回狀態處理程序 function 以便狀態處理程序可以更新 API 然后允許密集型 function 繼續計算而不會丟失任何堆棧(例如 it 變量和文件句柄)

我查看了 async function 但它們似乎只返回一次。

先感謝您!

異步實際上可以暫停和恢復,但它適用於 IO 綁定程序,這些程序基本上一直在等待一些外部 IO。 它不適用於計算繁重的任務

關於如何解決這個問題,我想到了兩種方法:

  • 線程和通道
  • 回調

解決方案 1:線程和通道

use std::{sync::mpsc, thread, time::Duration};

struct StatusUpdate {
    task_id: i32,
    percent: f32,
}
impl StatusUpdate {
    pub fn new(task_id: i32, percent: f32) -> Self {
        Self { task_id, percent }
    }
}

fn expensive_computation(id: i32, status_update: mpsc::Sender<StatusUpdate>) {
    status_update.send(StatusUpdate::new(id, 0.0)).unwrap();
    thread::sleep(Duration::from_millis(1000));
    status_update.send(StatusUpdate::new(id, 33.3)).unwrap();
    thread::sleep(Duration::from_millis(1000));
    status_update.send(StatusUpdate::new(id, 66.6)).unwrap();
    thread::sleep(Duration::from_millis(1000));
    status_update.send(StatusUpdate::new(id, 100.0)).unwrap();
}

fn main() {
    let (status_sender_1, status_receiver) = mpsc::channel();
    let status_sender_2 = status_sender_1.clone();

    thread::spawn(move || expensive_computation(1, status_sender_1));
    thread::spawn(move || expensive_computation(2, status_sender_2));

    for status_update in status_receiver {
        println!(
            "Task {} is done {} %",
            status_update.task_id, status_update.percent
        );
    }
}
Task 1 is done 0 %
Task 2 is done 0 %
Task 1 is done 33.3 %
Task 2 is done 33.3 %
Task 1 is done 66.6 %
Task 2 is done 66.6 %
Task 2 is done 100 %
Task 1 is done 100 %

解決方案 2:回調

use std::{thread, time::Duration};

struct StatusUpdate {
    task_id: i32,
    percent: f32,
}
impl StatusUpdate {
    pub fn new(task_id: i32, percent: f32) -> Self {
        Self { task_id, percent }
    }
}

fn expensive_computation<F: FnMut(StatusUpdate)>(id: i32, mut update_status: F) {
    update_status(StatusUpdate::new(id, 0.0));
    thread::sleep(Duration::from_millis(1000));
    update_status(StatusUpdate::new(id, 33.3));
    thread::sleep(Duration::from_millis(1000));
    update_status(StatusUpdate::new(id, 66.6));
    thread::sleep(Duration::from_millis(1000));
    update_status(StatusUpdate::new(id, 100.0));
}

fn main() {
    expensive_computation(1, |status_update| {
        println!(
            "Task {} is done {} %",
            status_update.task_id, status_update.percent
        );
    });
}
Task 1 is done 0 %
Task 1 is done 33.3 %
Task 1 is done 66.6 %
Task 1 is done 100 %

請注意,使用通道解決方案可以更輕松地同時處理不同線程上的多個計算。 使用回調,線程之間的通信很難/不可能。

我是否可以暫停執行昂貴的 function 而我對該數據執行某些操作然后允許它恢復?

不,這不是線程可以完成的事情。 一般來說。

您可以以低於主線程的優先級運行它們,這意味着它們不會被積極調度,從而減少主線程中的延遲。 但一般來說,操作系統是搶占式的,能夠在線程之間來回切換,所以你不必擔心“暫停”。

您要的是generators ,目前不穩定。 您可以在nightly上試驗它們,或者手動創建像它們一樣工作的東西並手動調用它(盡管它的語法不如生成器)。 例如這樣的事情:

enum Status<T, K> {
    Updated(T),
    Finished(K)
}

struct State { /* ... */ }

impl State {
    pub fn new() -> Self {
        Self { /* ... */ }
    }
    
    pub fn call(self) -> Status<Self, ()> {
        // Do some update on State and return
        // State::Updated(self). When you finised
        // return State::Finished(()). Note that this
        // method consumes self. You could make it take
        // &mut self, but then you would have to worry
        // about how to prevent it beeing called after
        // it finished. If you want to return some intermidiate
        // value in each step you can make Status::Updated
        // contain a (state, value) instead.
        
        todo!()
    }
}

fn foo() {
    let mut state = State::new();
    
    let result = loop {
        match state.call() {
            Status::Updated(s) => state = s,
            Status::Finished(result) => break result
        }
    };
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM