Coalesce concurrent native finder refreshes with the same key#1598
Open
StellaHuang95 wants to merge 1 commit into
Open
Coalesce concurrent native finder refreshes with the same key#1598StellaHuang95 wants to merge 1 commit into
StellaHuang95 wants to merge 1 commit into
Conversation
f6cb6e5 to
6806513
Compare
Contributor
Author
|
Rich verified he's no longer seeing something like this in the logs: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #1587.
At startup, several environment managers (venv, system, pyenv, pipenv, poetry, conda) each call
nativeFinder.refresh(true, undefined)concurrently — typically triggered when the Python extension callsapi.refreshEnvironments(undefined)via itstriggerRefreshon activation. Every one of those calls resolves to the same cache key ('all') but is queued as a distinct task on the native finder's worker pool, which runs withconcurrency = 1. Neither the worker pool nordoRefreshdeduplicates identical submissions, so N parallel callers become N sequential full PET discoveries — same input, same output, N-1 wasted scans.The reporter (pytorch workspace) saw the result of this stacking:
plus the
Setup appears hung during stage: managerRegistrationwatchdog firing, and the sameDiscovered env: <path>lines repeating 4-5× in the log — the smoking gun that PET ran the same scan multiple times back-to-back.Fix
Add an in-flight tracking map (
Map<string, Promise<NativeInfo[]>>) inNativePythonFinderImpland a guard at the top ofhandleHardRefresh: if a refresh for the same key is already running, return the existing promise instead of queueing another task. The slot is cleared in.finallyso a rejected refresh does not poison future callers — sequential refreshes still each run a fresh PET scan.handleSoftRefreshalready falls through tohandleHardRefreshon cache miss, so it picks up the dedup automatically — a concurrent soft + hard for the same key now share one PET scan.Why this layer
handleHardRefresh(manager refreshes, conda'sgetCondafallback vianative.refresh(false), the Python extension'striggerRefresh, theRefresh All Environment Managerscommand, external API consumers). Fixing here covers every caller in one place.inFlight: Map<string, Promise<…>>idiom insrc/features/inlineScriptLazyDetector.ts.Expected impact for #1587
Setup appears hung during stage: managerRegistrationThe fix eliminates duplicate-scan stacking; it does not speed up a single PET scan (intrinsic ~25-35 s on pytorch on the reporter''s machine — separate from this change).
Verification
main).main, diffed the minifiedhandleHardRefreshbody — the fix VSIX has the new structure (inFlightRefreshes.get → guard → addToQueue.then.finally),mainhas the old (await pool.addToQueue).Tested manually by inspecting the minified output of both builds; would appreciate eyes from someone with the pytorch repro to confirm wall-clock improvement on a real run.
What this does NOT address (intentionally)
triggerRefreshon every activation (worth a follow-up — could skip when our cache is non-empty).InternalEnvironmentManager.refresh''s tail-call togetEnvironments(''all'')(separate small follow-up; produces the "phantom" lowercase-only refresh log lines).Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com