Brief description of your issue
Packaged winget appears to serialize read-only opens of the preindexed winget source behind a single exclusive cross-process mutex. Under concurrent winget usage, commands that should be quick source reads can stall for tens of seconds or longer before doing meaningful work.
Steps to reproduce
Run several concurrent show commands and print elapsed time for each job:
$w = (Get-Command winget.exe).Source
1..6 | ForEach-Object {
$i = $_
Start-Job -ArgumentList $i, $w {
param($i, $w)
$s = [Diagnostics.Stopwatch]::StartNew()
& $w show --id Devolutions.RemoteDesktopManager --exact --source winget --disable-interactivity --accept-source-agreements *> $null
[pscustomobject]@{
Job = $i
Seconds = [math]::Round($s.Elapsed.TotalSeconds, 3)
ExitCode = $LASTEXITCODE
}
}
} | Wait-Job | Receive-Job | Sort-Object Job | Format-Table -AutoSize
Sample run
Job Seconds ExitCode
--- ------- --------
1 44.84 0
2 163.93 0
3 122.67 0
4 204.52 0
5 86.86 0
6 241.91 0
All six commands succeeded, but some waited several minutes.
Expected behavior
Read-only commands such as winget show and winget search should not block behind unrelated concurrent winget activity when they only need to open and read the packaged source index.
Actual behavior
The command often appears idle for a long time, then completes quickly once source open proceeds.
Analysis
The relevant path appears to be in:
src\AppInstallerRepositoryCore\Microsoft\PreIndexedPackageSourceFactory.cpp
src\AppInstallerCommonCore\Synchronization.cpp
src\AppInstallerRepositoryCore\RepositorySource.cpp
Observed behavior suggests that read-only packaged source open uses the same named cross-process mutex as source update/add/remove operations:
PreIndexedSourceCPL_Microsoft.Winget.Source_8wekyb3d8bbwe
In instrumented runs, the expensive part was the wait to acquire that mutex, not the actual source read work. Representative timings from local investigation:
- SQLite search: ~3-5 ms
- warm package version data load: ~6-10 ms
- warm manifest load: ~12-18 ms
- packaged source open once it proceeds: ~80-130 ms
- mutex wait in contended runs: ~10 s, ~26 s, and higher in multi-process runs
This creates a convoy effect:
- one process acquires the preindexed source mutex
- other processes queue behind it, including read-only commands
- the waiting time dominates wall-clock duration even though their own source read work is small
One detail that stood out while reading the code is that comments refer to a reader-writer lock, while the current implementation appears to use a plain exclusive mutex.
Impact
This likely affects more than winget show. Any command that opens the packaged winget source may be impacted, including:
winget search
winget show
winget install during package lookup / manifest resolution
winget upgrade during lookup / manifest resolution
winget download
For scripts or tools that invoke winget concurrently like UniGetUI, or just when developing winget locally with multiple AI agents running winget commands concurrently, this can cause highly variable latency and very large slowdowns in otherwise read-mostly workflows.
Brief description of your issue
Packaged
wingetappears to serialize read-only opens of the preindexedwingetsource behind a single exclusive cross-process mutex. Under concurrentwingetusage, commands that should be quick source reads can stall for tens of seconds or longer before doing meaningful work.Steps to reproduce
Run several concurrent
showcommands and print elapsed time for each job:Sample run
All six commands succeeded, but some waited several minutes.
Expected behavior
Read-only commands such as
winget showandwinget searchshould not block behind unrelated concurrentwingetactivity when they only need to open and read the packaged source index.Actual behavior
The command often appears idle for a long time, then completes quickly once source open proceeds.
Analysis
The relevant path appears to be in:
src\AppInstallerRepositoryCore\Microsoft\PreIndexedPackageSourceFactory.cppsrc\AppInstallerCommonCore\Synchronization.cppsrc\AppInstallerRepositoryCore\RepositorySource.cppObserved behavior suggests that read-only packaged source open uses the same named cross-process mutex as source update/add/remove operations:
In instrumented runs, the expensive part was the wait to acquire that mutex, not the actual source read work. Representative timings from local investigation:
This creates a convoy effect:
One detail that stood out while reading the code is that comments refer to a reader-writer lock, while the current implementation appears to use a plain exclusive mutex.
Impact
This likely affects more than
winget show. Any command that opens the packagedwingetsource may be impacted, including:winget searchwinget showwinget installduring package lookup / manifest resolutionwinget upgradeduring lookup / manifest resolutionwinget downloadFor scripts or tools that invoke
wingetconcurrently like UniGetUI, or just when developing winget locally with multiple AI agents running winget commands concurrently, this can cause highly variable latency and very large slowdowns in otherwise read-mostly workflows.