Accelerate current-view DXF export and keep desktop exports responsive (#1738)

Thanks @crono2250.
This commit is contained in:
cronos authored and GitHub committed 2026-10-16 10:26:27 -04:00
1 parent 4bacd0cae0
commit bba03803b7
20 files changed
+1319 -53

No files matched your search

+1 -1
View File
@@ -85,7 +85,7 @@ mod outline;
#[cfg(test)]
mod outline_tests;
mod par;
pub use par::{for_each_on_threads, map_on_threads};
pub use par::{for_each_on_threads, map_on_threads, map_with_local_pools};
#[cfg(test)]
mod pinch_tests;
mod planar_faces;
+44
View File
@@ -33,6 +33,37 @@ pub fn for_each_on_threads<T: Sync>(items: &[T], max_threads: usize, f: impl Fn(
let _ = map_on_threads(items, max_threads, f);
}
/// Independent kernel jobs, with one computation lane per native dispatcher. Each dispatcher
/// owns a single-thread Rayon pool: nested triangulation neither queues behind a common
/// one-thread pool nor multiplies the requested concurrency. No second body can be stolen by
/// a worker while it fills a shared lazy mesh cell. The browser runs serially.
pub fn map_with_local_pools<T: Sync, R: Send>(items: &[T], max_threads: usize, f: impl Fn(&T) -> Result<R> + Sync) -> Vec<Result<R>> {
#[cfg(not(target_arch = "wasm32"))]
let one = |item: &T| {
use std::cell::OnceCell;
thread_local! {
static POOL: OnceCell<rayon::ThreadPool> = const { OnceCell::new() };
}
POOL.with(|cell| {
if cell.get().is_none() {
let pool = rayon::ThreadPoolBuilder::new()
.num_threads(1)
.build()
.map_err(|e| crate::KernelError::Failed(format!("cannot start mesh worker: {e}")))?;
let _ = cell.set(pool);
}
let pool = cell.get().ok_or_else(|| crate::KernelError::Failed("missing mesh worker".into()))?;
pool.install(|| guard("mesh worker", || f(item)))
})
};
#[cfg(target_arch = "wasm32")]
let one = |item: &T| guard("mesh worker", || f(item));
map_on_threads(items, max_threads, one)
.into_iter()
.map(|r| r.unwrap_or_else(|| Err(crate::KernelError::Internal("mesh worker failed".into()))))
.collect()
}
/// `f` over `items` as [`for_each_on_threads`] runs it, results in item order (`None` where an
/// item panicked).
pub fn map_on_threads<T: Sync, R: Send>(items: &[T], max_threads: usize, f: impl Fn(&T) -> R + Sync) -> Vec<Option<R>> {
@@ -82,6 +113,19 @@ mod tests {
use super::*;
use crate::KernelError;
#[test]
fn local_pools_keep_order_and_errors_and_bound_nested_parallelism() {
let items: Vec<usize> = (0..32).collect();
let result = map_with_local_pools(&items, 8, |i| {
#[cfg(not(target_arch = "wasm32"))]
assert_eq!(rayon::current_num_threads(), 1);
if *i == 7 { Err(KernelError::Invalid("seven".into())) } else { Ok(*i * 2) }
});
for (i, r) in result.iter().enumerate() {
assert_eq!(r.as_ref().ok().copied(), (i != 7).then_some(i * 2));
}
}
#[test]
fn each_item_once_on_threads() {
let items: Vec<u32> = (0..1000).collect();
+1 -1
View File
@@ -34,7 +34,7 @@ pub fn watching<R>(watch: Arc<dyn Watch>, f: impl FnOnce() -> R) -> R {
}
/// The watch over this thread's work, to hand to the worker threads it starts.
pub(crate) fn current() -> Option<Arc<dyn Watch>> {
pub fn current() -> Option<Arc<dyn Watch>> {
CURRENT.with(|c| c.borrow().clone())
}