Accelerate current-view DXF export and keep desktop exports responsive (#1738)
Thanks @crono2250.
This commit is contained in:
1 parent
4bacd0cae0
commit
bba03803b7
20 files changed
+1319
-53
No files matched your search
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user