rust 将对象存储在静态Box中,然后作为可变对象检索?

piv4azn7  于 2023-11-19  发布在  其他
关注(0)|答案(1)|浏览(73)

这是一个PyO3的情况。所以Python调用一个长时间运行的任务。使用ZeroMQ消息传递(进程间消息传递 *)用户可以命令任务挂起。此时,我想将“handling framework”对象存储在static框中,以便用户可能稍后单击“Resume”,通过这样做,回到Rust,在第二次调用时,框架对象可以从这个static框中检索,并从它停止的地方重新开始工作。2这样做的最大好处是框架的状态可以被保留。
让我感到惊讶的是,Rust内存中的static结构似乎在Python调用PyO3函数之间保留了下来。
这就是我如何在检测到“suspend”命令时“填充”框架:

static SUSPENDED_FRAMEWORK_OPTION: OnceLock<Box<HandlingFramework>> = OnceLock::new();
...
let mut handling_framework = HandlingFramework::new(op_type, index_name, dir_root_path_str, current_app_version, current_index_version, tx_zero_client);
handling_framework.init()?; 
let (job_suspended_state, total_word_count, total_ldoc_count) = handling_framework.index_docs()?;
if std::matches!(job_suspended_state, JobSuspendedState::Suspended) {
    let _ = SUSPENDED_FRAMEWORK_OPTION.set(Box::new(handling_framework))
}

字符串
.这就是我试图在稍后的PyO3调用中检索框架的方式:

if op_type == "RESUME".to_string(){
    let option_for_framework = SUSPENDED_FRAMEWORK_OPTION.get();
    let framework_box_ref = option_for_framework.unwrap();
    info!("text_doc_hit_objs_for_processing remaining {}", framework_box_ref.text_doc_hit_objs_for_processing.len());
    info!("framework_box_ref type {}", str_type_of(&framework_box_ref));


给出framework_box_ref type &alloc::boxed::Box<populate_index::handling_framework::HandlingFramework>
这在某种意义上是可行的,我能够获得对检索到的框架中的各种对象的读访问。
但是要做任何有用的事情(恢复处理),我需要对框架对象有可变的访问权限。我在那里尝试的一切都失败了,通常是沿着“不能移出共享引用”的线路。
我试过这样的方法:

fn unbox<T>(value: Box<T>) -> T {
    *value
}
let mut framework = unbox(*framework_box_ref);


这给出:

error[E0507]: cannot move out of `*framework_box_ref` which is behind a shared reference
   --> src\lib.rs:114:29
    |
114 |         let mut framework = unbox(*framework_box_ref);
    |                                   ^^^^^^^^^^^^^^^^^^ move occurs because `*framework_box_ref` has type `Box<HandlingFramework>`, which does not implement the `Copy` trait


有人能建议如何获得这个可变变量吗?目前HandlingFramework不实现CopyClone.我已经尝试derive这些,但有太多的内部字段不实现一个或两个。我可以潜在地实现一个或两个“手动”,如果需要的话,但目前我希望获得可变访问没有...

  • 实际上,这不是进程间消息传递,而是线程间消息传递:Rust代码似乎与调用它的Python工作线程在同一个线程中运行。因此,另一个Python线程被用来发送消息。
2guxujil

2guxujil1#

如果没有某种内部可变性,就无法写入OnceLock中的值,此时您应该使用它而不是OnceLock。请注意,无论如何都不能从引用移动,即使是&mut;要做到这一点,您需要交换一些东西,以便referent仍然有效。
也不清楚为什么你需要一个Box
可以考虑使用Mutex<Option<_>>。您可以使用Option::take来“窃取”Option的内容,而留下None

static SUSPENDED_FRAMEWORK_OPTION: Mutex<Option<HandlingFramework>> = Mutex::new(None);

// ...

if std::matches!(job_suspended_state, JobSuspendedState::Suspended) {
    *SUSPENDED_FRAMEWORK_OPTION.lock().unwrap() = Some(handling_framework);
}

字符串
稍后,您可以像这样取出值:

let mut framework = SUSPENDED_FRAMEWORK_OPTION
    .lock()
    .unwrap()
    .take()
    .expect("SUSPENDED_FRAMEWORK_OPTION was None");


然而,我强烈反对像这样使用全局状态。最好将此值隐藏在表示框架状态的Python对象中,然后您可以从那里获取它,而不需要全局状态。

相关问题