将自动切分状态写盘移出 Tokio worker

用 spawn_blocking 承载 JSON 序列化和文件写入,并在工作流中等待结果。
This commit is contained in:
2026-09-11 19:44:01 +08:00
parent 4cf3642b53
commit 8c8b6cc75a
2 changed files with 21 additions and 13 deletions
@@ -42,7 +42,13 @@ pub fn project_relative_path(root: &Path, path: &Path) -> Result<String, String>
Ok(value)
}
pub fn write_separation_state(path: &Path, state: &SeparationState) -> Result<(), String> {
pub async fn write_separation_state(path: PathBuf, state: SeparationState) -> Result<(), String> {
tokio::task::spawn_blocking(move || write_separation_state_blocking(&path, &state))
.await
.map_err(|error| format!("写入 separation state 任务失败:{error}"))?
}
fn write_separation_state_blocking(path: &Path, state: &SeparationState) -> Result<(), String> {
if state.schema_version != SEPARATION_STATE_SCHEMA_VERSION {
app_log!("ui_separation.error stage=state_write reason=schema_mismatch");
return Err("不支持的 separation state schema".to_string());
@@ -98,13 +98,15 @@ pub(crate) async fn separate_ui_impl(
image.pixel_size.x.round() as u32,
image.pixel_size.y.round() as u32
);
write_separation_state(&state_path, &separation).map_err(|error| {
app_log!(
"ui_separation.error stage=state_checkpoint tree_index={} error={error}",
tree_index
);
error
})?;
write_separation_state(state_path.clone(), separation.clone())
.await
.map_err(|error| {
app_log!(
"ui_separation.error stage=state_checkpoint tree_index={} error={error}",
tree_index
);
error
})?;
let mut batch_index = 0usize;
loop {
let batch_started = Instant::now();
@@ -146,7 +148,7 @@ pub(crate) async fn separate_ui_impl(
Ok(value) => value,
Err(error) => {
app_log!("ui_separation.error stage=image_edit tree_index={} batch_index={} error={error}", tree_index, batch_index);
write_separation_state(&state_path, &separation)?;
write_separation_state(state_path.clone(), separation.clone()).await?;
return Err(error);
}
};
@@ -155,7 +157,7 @@ pub(crate) async fn separate_ui_impl(
extract::write_processed_image(processed_url.clone(), processed_path.clone()).await
{
app_log!("ui_separation.error stage=processed_image_write tree_index={} batch_index={} error={error}", tree_index, batch_index);
write_separation_state(&state_path, &separation)?;
write_separation_state(state_path.clone(), separation.clone()).await?;
return Err(error);
}
let binding = match binding::visual_binding(
@@ -169,7 +171,7 @@ pub(crate) async fn separate_ui_impl(
Ok(value) => value,
Err(error) => {
app_log!("ui_separation.error stage=visual_binding tree_index={} batch_index={} error={error}", tree_index, batch_index);
write_separation_state(&state_path, &separation)?;
write_separation_state(state_path.clone(), separation.clone()).await?;
return Err(error);
}
};
@@ -220,11 +222,11 @@ pub(crate) async fn separate_ui_impl(
}
if let Some(error) = cut_error {
app_log!("ui_separation.error stage=cut_batch tree_index={} batch_index={} error={error}", tree_index, batch_index);
write_separation_state(&state_path, &separation)?;
write_separation_state(state_path.clone(), separation.clone()).await?;
return Err(error);
}
patch::apply_batch_patch(&mut separation, tree_index, &binding.decisions, &cut_paths)?;
write_separation_state(&state_path, &separation)?;
write_separation_state(state_path.clone(), separation.clone()).await?;
app_log!(
"ui_separation.batch_completed tree_index={} batch_index={} cuts={} bound={} problematic={} elapsed_ms={}",
tree_index, batch_index, cut_paths.len(), separation.bound.len(), separation.problematic_nodes.len(), batch_started.elapsed().as_millis()