From f632a4b773a2a5f4b229685e6139f7ac843bf08c Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 26 Oct 2025 20:59:29 +0800 Subject: [PATCH] Add caching to QueryAsync and integrate cache reset logic Introduced a MemoryCache to improve QueryAsync performance by caching query results, reducing redundant computations. Added a ResetCache method to reinitialize the cache when settings are updated. Integrated cache reset calls into settings property setters to ensure consistency. Refactored query logic to leverage MemoryCache.GetOrCreateAsync for streamlined caching. Removed redundant code and debug logging for improved readability and maintainability. Ensured thread safety with proper locking mechanisms. Simplified and consolidated caching logic for better maintainability. --- Plugins/Flow.Launcher.Plugin.Program/Main.cs | 90 +++++++++++-------- .../Views/ProgramSetting.xaml.cs | 4 + 2 files changed, 57 insertions(+), 37 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs index e8554198e..bb850b4de 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Main.cs @@ -35,6 +35,9 @@ namespace Flow.Launcher.Plugin.Program private static readonly List emptyResults = []; + private static readonly MemoryCacheOptions cacheOptions = new() { SizeLimit = 1560 }; + private static MemoryCache cache = new(cacheOptions); + private static readonly string[] commonUninstallerNames = { "uninst.exe", @@ -77,45 +80,53 @@ namespace Flow.Launcher.Plugin.Program public async Task> QueryAsync(Query query, CancellationToken token) { - var resultList = await Task.Run(async () => + var result = await cache.GetOrCreateAsync(query.Search, async entry => { - await _win32sLock.WaitAsync(token); - await _uwpsLock.WaitAsync(token); - try + var resultList = await Task.Run(async () => { - // Collect all UWP Windows app directories - var uwpsDirectories = _settings.HideDuplicatedWindowsApp ? _uwps - .Where(uwp => !string.IsNullOrEmpty(uwp.Location)) // Exclude invalid paths - .Where(uwp => uwp.Location.StartsWith(WindowsAppPath, StringComparison.OrdinalIgnoreCase)) // Keep system apps - .Select(uwp => uwp.Location.TrimEnd('\\')) // Remove trailing slash - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToArray() : null; - - return _win32s.Cast() - .Concat(_uwps) - .AsParallel() - .WithCancellation(token) - .Where(HideUninstallersFilter) - .Where(p => HideDuplicatedWindowsAppFilter(p, uwpsDirectories)) - .Where(p => p.Enabled) - .Select(p => p.Result(query.Search, Context.API)) - .Where(r => string.IsNullOrEmpty(query.Search) || r?.Score > 0) - .ToList(); - } - catch (OperationCanceledException) - { - return emptyResults; - } - finally - { - _uwpsLock.Release(); - _win32sLock.Release(); - } - }, token); + await _win32sLock.WaitAsync(token); + await _uwpsLock.WaitAsync(token); + try + { + // Collect all UWP Windows app directories + var uwpsDirectories = _settings.HideDuplicatedWindowsApp ? _uwps + .Where(uwp => !string.IsNullOrEmpty(uwp.Location)) // Exclude invalid paths + .Where(uwp => uwp.Location.StartsWith(WindowsAppPath, StringComparison.OrdinalIgnoreCase)) // Keep system apps + .Select(uwp => uwp.Location.TrimEnd('\\')) // Remove trailing slash + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToArray() : null; - resultList = resultList.Count != 0 ? resultList : emptyResults; + return _win32s.Cast() + .Concat(_uwps) + .AsParallel() + .WithCancellation(token) + .Where(HideUninstallersFilter) + .Where(p => HideDuplicatedWindowsAppFilter(p, uwpsDirectories)) + .Where(p => p.Enabled) + .Select(p => p.Result(query.Search, Context.API)) + .Where(r => string.IsNullOrEmpty(query.Search) || r?.Score > 0) + .ToList(); + } + catch (OperationCanceledException) + { + return emptyResults; + } + finally + { + _uwpsLock.Release(); + _win32sLock.Release(); + } + }, token); - return resultList; + resultList = resultList.Count != 0 ? resultList : emptyResults; + + entry.SetSize(resultList.Count); + entry.SetSlidingExpiration(TimeSpan.FromHours(8)); + + return resultList; + }); + + return result; } private bool HideUninstallersFilter(IProgram program) @@ -305,7 +316,6 @@ namespace Flow.Launcher.Plugin.Program { _win32s.Add(win32); } - Context.API.LogDebug(ClassName, "Cache all Win32 programs"); await Context.API.SaveCacheBinaryStorageAsync>(Win32CacheName, Context.CurrentPluginMetadata.PluginCacheDirectoryPath); lock (_lastIndexTimeLock) { @@ -337,7 +347,6 @@ namespace Flow.Launcher.Plugin.Program { _uwps.Add(uwp); } - Context.API.LogDebug(ClassName, "Cache all Uwp programs"); await Context.API.SaveCacheBinaryStorageAsync>(UwpCacheName, Context.CurrentPluginMetadata.PluginCacheDirectoryPath); lock (_lastIndexTimeLock) { @@ -372,6 +381,13 @@ namespace Flow.Launcher.Plugin.Program await Task.WhenAll(win32Task, uwpTask).ConfigureAwait(false); } + internal static void ResetCache() + { + var oldCache = cache; + cache = new MemoryCache(cacheOptions); + oldCache.Dispose(); + } + public Control CreateSettingPanel() { return new ProgramSetting(Context, _settings); diff --git a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs index 8770dd651..860f20954 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs @@ -32,6 +32,7 @@ namespace Flow.Launcher.Plugin.Program.Views get => _settings.EnableDescription; set { + Main.ResetCache(); _settings.EnableDescription = value; } } @@ -41,6 +42,7 @@ namespace Flow.Launcher.Plugin.Program.Views get => _settings.HideAppsPath; set { + Main.ResetCache(); _settings.HideAppsPath = value; } } @@ -50,6 +52,7 @@ namespace Flow.Launcher.Plugin.Program.Views get => _settings.HideUninstallers; set { + Main.ResetCache(); _settings.HideUninstallers = value; } } @@ -59,6 +62,7 @@ namespace Flow.Launcher.Plugin.Program.Views get => _settings.HideDuplicatedWindowsApp; set { + Main.ResetCache(); _settings.HideDuplicatedWindowsApp = value; } }