Use Task.Yield to avoid using Parallel.For

This commit is contained in:
张弘韬 2021-01-09 12:01:08 +08:00
parent c939924ec8
commit 92be6fd3dd

View file

@ -86,7 +86,7 @@ namespace Flow.Launcher.ViewModel
{ {
foreach (var pair in PluginManager.GetPluginsForInterface<IResultUpdated>()) foreach (var pair in PluginManager.GetPluginsForInterface<IResultUpdated>())
{ {
var plugin = (IResultUpdated)pair.Plugin; var plugin = (IResultUpdated) pair.Plugin;
plugin.ResultsUpdated += (s, e) => plugin.ResultsUpdated += (s, e) =>
{ {
Task.Run(() => Task.Run(() =>
@ -113,25 +113,13 @@ namespace Flow.Launcher.ViewModel
} }
}); });
SelectNextItemCommand = new RelayCommand(_ => SelectNextItemCommand = new RelayCommand(_ => { SelectedResults.SelectNextResult(); });
{
SelectedResults.SelectNextResult();
});
SelectPrevItemCommand = new RelayCommand(_ => SelectPrevItemCommand = new RelayCommand(_ => { SelectedResults.SelectPrevResult(); });
{
SelectedResults.SelectPrevResult();
});
SelectNextPageCommand = new RelayCommand(_ => SelectNextPageCommand = new RelayCommand(_ => { SelectedResults.SelectNextPage(); });
{
SelectedResults.SelectNextPage();
});
SelectPrevPageCommand = new RelayCommand(_ => SelectPrevPageCommand = new RelayCommand(_ => { SelectedResults.SelectPrevPage(); });
{
SelectedResults.SelectPrevPage();
});
SelectFirstResultCommand = new RelayCommand(_ => SelectedResults.SelectFirstResult()); SelectFirstResultCommand = new RelayCommand(_ => SelectedResults.SelectFirstResult());
@ -209,6 +197,7 @@ namespace Flow.Launcher.ViewModel
public ResultsViewModel History { get; private set; } public ResultsViewModel History { get; private set; }
private string _queryText; private string _queryText;
public string QueryText public string QueryText
{ {
get { return _queryText; } get { return _queryText; }
@ -229,10 +218,12 @@ namespace Flow.Launcher.ViewModel
QueryTextCursorMovedToEnd = true; QueryTextCursorMovedToEnd = true;
QueryText = queryText; QueryText = queryText;
} }
public bool LastQuerySelected { get; set; } public bool LastQuerySelected { get; set; }
public bool QueryTextCursorMovedToEnd { get; set; } public bool QueryTextCursorMovedToEnd { get; set; }
private ResultsViewModel _selectedResults; private ResultsViewModel _selectedResults;
private ResultsViewModel SelectedResults private ResultsViewModel SelectedResults
{ {
get { return _selectedResults; } get { return _selectedResults; }
@ -264,6 +255,7 @@ namespace Flow.Launcher.ViewModel
QueryText = string.Empty; QueryText = string.Empty;
} }
} }
_selectedResults.Visbility = Visibility.Visible; _selectedResults.Visbility = Visibility.Visible;
} }
} }
@ -324,7 +316,7 @@ namespace Flow.Launcher.ViewModel
var filtered = results.Where var filtered = results.Where
( (
r => StringMatcher.FuzzySearch(query, r.Title).IsSearchPrecisionScoreMet() r => StringMatcher.FuzzySearch(query, r.Title).IsSearchPrecisionScoreMet()
|| StringMatcher.FuzzySearch(query, r.SubTitle).IsSearchPrecisionScoreMet() || StringMatcher.FuzzySearch(query, r.SubTitle).IsSearchPrecisionScoreMet()
).ToList(); ).ToList();
ContextMenu.AddResults(filtered, id); ContextMenu.AddResults(filtered, id);
} }
@ -351,7 +343,7 @@ namespace Flow.Launcher.ViewModel
Title = string.Format(title, h.Query), Title = string.Format(title, h.Query),
SubTitle = string.Format(time, h.ExecutedDateTime), SubTitle = string.Format(time, h.ExecutedDateTime),
IcoPath = "Images\\history.png", IcoPath = "Images\\history.png",
OriginQuery = new Query { RawQuery = h.Query }, OriginQuery = new Query {RawQuery = h.Query},
Action = _ => Action = _ =>
{ {
SelectedResults = Results; SelectedResults = Results;
@ -397,7 +389,8 @@ namespace Flow.Launcher.ViewModel
_lastQuery = query; _lastQuery = query;
Task.Delay(200, currentCancellationToken).ContinueWith(_ => Task.Delay(200, currentCancellationToken).ContinueWith(_ =>
{ // start the progress bar if query takes more than 200 ms and this is the current running query and it didn't finish yet {
// start the progress bar if query takes more than 200 ms and this is the current running query and it didn't finish yet
if (currentUpdateSource == _updateSource && _isQueryRunning) if (currentUpdateSource == _updateSource && _isQueryRunning)
{ {
ProgressBarVisibility = Visibility.Visible; ProgressBarVisibility = Visibility.Visible;
@ -410,17 +403,14 @@ namespace Flow.Launcher.ViewModel
// so looping will stop once it was cancelled // so looping will stop once it was cancelled
Task[] tasks = new Task[plugins.Count]; Task[] tasks = new Task[plugins.Count];
var parallelOptions = new ParallelOptions { CancellationToken = currentCancellationToken };
try try
{ {
Parallel.For(0, plugins.Count, parallelOptions, i => for (var i = 0; i < plugins.Count; i++)
{ {
if (!plugins[i].Metadata.Disabled) if (!plugins[i].Metadata.Disabled)
{
tasks[i] = QueryTask(plugins[i], query, currentCancellationToken); tasks[i] = QueryTask(plugins[i], query, currentCancellationToken);
}
else tasks[i] = Task.CompletedTask; // Avoid Null else tasks[i] = Task.CompletedTask; // Avoid Null
}); }
// Check the code, WhenAll will translate all type of IEnumerable or Collection to Array, so make an array at first // Check the code, WhenAll will translate all type of IEnumerable or Collection to Array, so make an array at first
await Task.WhenAll(tasks); await Task.WhenAll(tasks);
@ -434,20 +424,25 @@ namespace Flow.Launcher.ViewModel
// until the end of all querying // until the end of all querying
_isQueryRunning = false; _isQueryRunning = false;
if (!currentCancellationToken.IsCancellationRequested) if (!currentCancellationToken.IsCancellationRequested)
{ // update to hidden if this is still the current query {
// update to hidden if this is still the current query
ProgressBarVisibility = Visibility.Hidden; ProgressBarVisibility = Visibility.Hidden;
} }
// Local Function // Local Function
async Task QueryTask(PluginPair plugin, Query query, CancellationToken token) async Task QueryTask(PluginPair plugin, Query query, CancellationToken token)
{ {
// Since it is wrapped within a Task.Run, the synchronous context is null
// Task.Yield will force it to run in ThreadPool
await Task.Yield();
var results = await PluginManager.QueryForPlugin(plugin, query, token); var results = await PluginManager.QueryForPlugin(plugin, query, token);
if (!currentCancellationToken.IsCancellationRequested) if (!currentCancellationToken.IsCancellationRequested)
UpdateResultView(results, plugin.Metadata, query); UpdateResultView(results, plugin.Metadata, query);
} }
}, currentCancellationToken).ContinueWith(
}, currentCancellationToken).ContinueWith(t => Log.Exception("|MainViewModel|Plugins Query Exceptions", t.Exception), t => Log.Exception("|MainViewModel|Plugins Query Exceptions", t.Exception),
TaskContinuationOptions.OnlyOnFaulted); TaskContinuationOptions.OnlyOnFaulted);
} }
} }
else else
@ -514,6 +509,7 @@ namespace Flow.Launcher.ViewModel
} }
}; };
} }
return menu; return menu;
} }
@ -559,6 +555,7 @@ namespace Flow.Launcher.ViewModel
var selected = SelectedResults == History; var selected = SelectedResults == History;
return selected; return selected;
} }
#region Hotkey #region Hotkey
private void SetHotkey(string hotkeyStr, EventHandler<HotkeyEventArgs> action) private void SetHotkey(string hotkeyStr, EventHandler<HotkeyEventArgs> action)
@ -577,7 +574,8 @@ namespace Flow.Launcher.ViewModel
catch (Exception) catch (Exception)
{ {
string errorMsg = string errorMsg =
string.Format(InternationalizationManager.Instance.GetTranslation("registerHotkeyFailed"), hotkeyStr); string.Format(InternationalizationManager.Instance.GetTranslation("registerHotkeyFailed"),
hotkeyStr);
MessageBox.Show(errorMsg); MessageBox.Show(errorMsg);
} }
} }
@ -627,7 +625,6 @@ namespace Flow.Launcher.ViewModel
{ {
if (!ShouldIgnoreHotkeys()) if (!ShouldIgnoreHotkeys())
{ {
if (_settings.LastQueryMode == LastQueryMode.Empty) if (_settings.LastQueryMode == LastQueryMode.Empty)
{ {
ChangeQueryText(string.Empty); ChangeQueryText(string.Empty);