From 65b80ff689022b50bc5c2e52dff94c51c8f2f79c Mon Sep 17 00:00:00 2001 From: MostlyK <135974627+MostlyKIGuess@users.noreply.github.com> Date: Wed, 18 Mar 2026 05:09:11 +0530 Subject: [PATCH] repl: Avoid duplicate kernelspec fetches (#51024) Switch python_env_kernel_specifications to a buffered stream (using buffer_unordered(4) and filter_map) to run discovery concurrently with a bounded parallelism and skip None results. Closes #50988 Before you mark this PR as ready for review, make sure that you have: - [x] Added a solid test coverage and/or screenshots from doing manual testing - [x] Done a self-review taking into account security and performance aspects - [x] Aligned any UI changes with the [UI checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) Release Notes: - N/A --- crates/repl/src/kernels/mod.rs | 10 +++++----- crates/repl/src/repl_store.rs | 20 ++++++++++++++++---- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/crates/repl/src/kernels/mod.rs b/crates/repl/src/kernels/mod.rs index 0f1ee9dabebe03b3735bfb95ab0e620a914de1e0..6745bcd9b6a08cb34b3a0fc3b8219918cb4f0dca 100644 --- a/crates/repl/src/kernels/mod.rs +++ b/crates/repl/src/kernels/mod.rs @@ -503,11 +503,11 @@ pub fn python_env_kernel_specifications( }); #[allow(unused_mut)] - let mut kernel_specs: Vec = futures::future::join_all(kernelspecs) - .await - .into_iter() - .flatten() - .collect(); + let mut kernel_specs: Vec = futures::stream::iter(kernelspecs) + .buffer_unordered(4) + .filter_map(|x| async move { x }) + .collect::>() + .await; #[cfg(target_os = "windows")] if kernel_specs.is_empty() && !is_remote { diff --git a/crates/repl/src/repl_store.rs b/crates/repl/src/repl_store.rs index 800bab030143de70f08ce2c020bd3095b6767e16..cf992a542830bd86c1a9ad8b1909501417f427fd 100644 --- a/crates/repl/src/repl_store.rs +++ b/crates/repl/src/repl_store.rs @@ -32,6 +32,7 @@ pub struct ReplStore { kernel_specifications_for_worktree: HashMap>, active_python_toolchain_for_worktree: HashMap, remote_worktrees: HashSet, + fetching_python_kernelspecs: HashSet, _subscriptions: Vec, } @@ -66,6 +67,7 @@ impl ReplStore { selected_kernel_for_worktree: HashMap::default(), active_python_toolchain_for_worktree: HashMap::default(), remote_worktrees: HashSet::default(), + fetching_python_kernelspecs: HashSet::default(), }; this.on_enabled_changed(cx); this @@ -140,6 +142,10 @@ impl ReplStore { project: &Entity, cx: &mut Context, ) -> Task> { + if !self.fetching_python_kernelspecs.insert(worktree_id) { + return Task::ready(Ok(())); + } + let is_remote = project.read(cx).is_remote(); // WSL does require access to global kernel specs, so we only exclude remote worktrees that aren't WSL. // TODO: a better way to handle WSL vs SSH/remote projects, @@ -149,7 +155,7 @@ impl ReplStore { .map_or(false, |opts| { matches!(opts, RemoteConnectionOptions::Wsl(_)) }); - let kernel_specifications = python_env_kernel_specifications(project, worktree_id, cx); + let kernel_specifications_task = python_env_kernel_specifications(project, worktree_id, cx); let active_toolchain = project.read(cx).active_toolchain( ProjectPath { worktree_id, @@ -160,9 +166,15 @@ impl ReplStore { ); cx.spawn(async move |this, cx| { - let kernel_specifications = kernel_specifications - .await - .context("getting python kernelspecs")?; + let kernel_specifications_res = kernel_specifications_task.await; + + this.update(cx, |this, _cx| { + this.fetching_python_kernelspecs.remove(&worktree_id); + }) + .ok(); + + let kernel_specifications = + kernel_specifications_res.context("getting python kernelspecs")?; let active_toolchain_path = active_toolchain.await.map(|toolchain| toolchain.path);