C# 多次执行异步eventhandler
我有一个eventhandler,可以执行多次。当我让它完成执行时,一切正常(只键入一个字符,然后等待计算结果)。 但当我正常输入时,就会出现死锁。至少我认为这是一个僵局C# 多次执行异步eventhandler,c#,wpf,task-parallel-library,async-await,deadlock,C#,Wpf,Task Parallel Library,Async Await,Deadlock,我有一个eventhandler,可以执行多次。当我让它完成执行时,一切正常(只键入一个字符,然后等待计算结果)。 但当我正常输入时,就会出现死锁。至少我认为这是一个僵局 private async void tbInput_TextChanged(object sender, TextChangedEventArgs e) { resultStackPanel.Children.Clear(); List<Task<UIElement>> tasks =
private async void tbInput_TextChanged(object sender, TextChangedEventArgs e)
{
resultStackPanel.Children.Clear();
List<Task<UIElement>> tasks = new List<Task<UIElement>>();
if (tbInput.Text != "")
{
foreach (IModule mod in Modules)
{
if (mod.IsApplicable(tbInput.Text))
tasks.Add(mod.CalculateOutcome(tbInput.Text));
}
while (tasks.Count > 0)
{
await Task.WhenAny(tasks);
foreach (Task<UIElement> resultTask in tasks)
{
if (resultTask.Status == TaskStatus.RanToCompletion)
{
if (resultTask.Result != null)
{
resultStackPanel.Children.Add(resultTask.Result);
}
tasks.Remove(resultTask);
break;
}
}
}
}
}
您只需向正在调用的异步方法添加一个延续,然后异步等待所有这些方法通过
任务完成。whalll
:
foreach (IModule mod in Modules)
{
if (mod.IsApplicable(tbInput.Text))
{
tasks.Add(mod.CalculateOutcome(tbInput.Text).ContinueWith(resultTask =>
{
if (resultTask.Result != null)
{
resultStackPanel.Children.Add(resultTask.Result);
}
}, TaskContinuationOptions.OnlyOnRanToCompletion));
}
}
await Task.WhenAll(tasks.ToArray());
您只需向正在调用的异步方法添加一个延续,然后异步等待所有这些方法通过
任务完成。whalll
:
foreach (IModule mod in Modules)
{
if (mod.IsApplicable(tbInput.Text))
{
tasks.Add(mod.CalculateOutcome(tbInput.Text).ContinueWith(resultTask =>
{
if (resultTask.Result != null)
{
resultStackPanel.Children.Add(resultTask.Result);
}
}, TaskContinuationOptions.OnlyOnRanToCompletion));
}
}
await Task.WhenAll(tasks.ToArray());
您只需向正在调用的异步方法添加一个延续,然后异步等待所有这些方法通过
任务完成。whalll
:
foreach (IModule mod in Modules)
{
if (mod.IsApplicable(tbInput.Text))
{
tasks.Add(mod.CalculateOutcome(tbInput.Text).ContinueWith(resultTask =>
{
if (resultTask.Result != null)
{
resultStackPanel.Children.Add(resultTask.Result);
}
}, TaskContinuationOptions.OnlyOnRanToCompletion));
}
}
await Task.WhenAll(tasks.ToArray());
您只需向正在调用的异步方法添加一个延续,然后异步等待所有这些方法通过
任务完成。whalll
:
foreach (IModule mod in Modules)
{
if (mod.IsApplicable(tbInput.Text))
{
tasks.Add(mod.CalculateOutcome(tbInput.Text).ContinueWith(resultTask =>
{
if (resultTask.Result != null)
{
resultStackPanel.Children.Add(resultTask.Result);
}
}, TaskContinuationOptions.OnlyOnRanToCompletion));
}
}
await Task.WhenAll(tasks.ToArray());
我可以看到您的代码存在一些问题。首先,如果任何任务没有成功完成,您将得到一个无限循环。另一方面,现有任务仍将运行到完成,并尝试更新UI 由于您的库不支持
CancellationToken
,因此您实际上无法取消操作(这很糟糕)。但你至少可以假装取消它们,让它们运行到完成,然后忽略结果。你可以使用我所说的技巧
将这样的逻辑拆分为另一种方法更容易,而不是使用延续;大概是这样的:
private object _callbackContext;
private async void tbInput_TextChanged(object sender, TextChangedEventArgs e)
{
_callbackContext = new object();
resultStackPanel.Children.Clear();
if (tbInput.Text == "")
return;
Modules.Where(mod => mod.IsApplicable(tbInput.Text))
.Select(mod => ApplyModuleAsync(mod));
}
private async Task ApplyModuleAsync(IModule module)
{
var myContext = _callbackContext;
var element = await module.CalculateOutcome(tbInput.Text);
if (myContext != _callbackContext || element == null)
return;
resultStackPanel.Children.Add(element);
}
我可以看到您的代码存在一些问题。首先,如果任何任务没有成功完成,您将得到一个无限循环。另一方面,现有任务仍将运行到完成,并尝试更新UI 由于您的库不支持
CancellationToken
,因此您实际上无法取消操作(这很糟糕)。但你至少可以假装取消它们,让它们运行到完成,然后忽略结果。你可以使用我所说的技巧
将这样的逻辑拆分为另一种方法更容易,而不是使用延续;大概是这样的:
private object _callbackContext;
private async void tbInput_TextChanged(object sender, TextChangedEventArgs e)
{
_callbackContext = new object();
resultStackPanel.Children.Clear();
if (tbInput.Text == "")
return;
Modules.Where(mod => mod.IsApplicable(tbInput.Text))
.Select(mod => ApplyModuleAsync(mod));
}
private async Task ApplyModuleAsync(IModule module)
{
var myContext = _callbackContext;
var element = await module.CalculateOutcome(tbInput.Text);
if (myContext != _callbackContext || element == null)
return;
resultStackPanel.Children.Add(element);
}
我可以看到您的代码存在一些问题。首先,如果任何任务没有成功完成,您将得到一个无限循环。另一方面,现有任务仍将运行到完成,并尝试更新UI 由于您的库不支持
CancellationToken
,因此您实际上无法取消操作(这很糟糕)。但你至少可以假装取消它们,让它们运行到完成,然后忽略结果。你可以使用我所说的技巧
将这样的逻辑拆分为另一种方法更容易,而不是使用延续;大概是这样的:
private object _callbackContext;
private async void tbInput_TextChanged(object sender, TextChangedEventArgs e)
{
_callbackContext = new object();
resultStackPanel.Children.Clear();
if (tbInput.Text == "")
return;
Modules.Where(mod => mod.IsApplicable(tbInput.Text))
.Select(mod => ApplyModuleAsync(mod));
}
private async Task ApplyModuleAsync(IModule module)
{
var myContext = _callbackContext;
var element = await module.CalculateOutcome(tbInput.Text);
if (myContext != _callbackContext || element == null)
return;
resultStackPanel.Children.Add(element);
}
我可以看到您的代码存在一些问题。首先,如果任何任务没有成功完成,您将得到一个无限循环。另一方面,现有任务仍将运行到完成,并尝试更新UI 由于您的库不支持
CancellationToken
,因此您实际上无法取消操作(这很糟糕)。但你至少可以假装取消它们,让它们运行到完成,然后忽略结果。你可以使用我所说的技巧
将这样的逻辑拆分为另一种方法更容易,而不是使用延续;大概是这样的:
private object _callbackContext;
private async void tbInput_TextChanged(object sender, TextChangedEventArgs e)
{
_callbackContext = new object();
resultStackPanel.Children.Clear();
if (tbInput.Text == "")
return;
Modules.Where(mod => mod.IsApplicable(tbInput.Text))
.Select(mod => ApplyModuleAsync(mod));
}
private async Task ApplyModuleAsync(IModule module)
{
var myContext = _callbackContext;
var element = await module.CalculateOutcome(tbInput.Text);
if (myContext != _callbackContext || element == null)
return;
resultStackPanel.Children.Add(element);
}
为什么不直接使用Task.whalll。如果你想在结果一出来就处理它们,你可以在每个任务上附加一个
ContinueWith
。为什么不直接使用Task.whalll
。如果你想在结果一出来就处理它们,你可以在每个任务上附加一个ContinueWith
。为什么不直接使用Task.whalll
。如果你想在结果一出来就处理它们,你可以在每个任务上附加一个ContinueWith
。为什么不直接使用Task.whalll
。如果你想在结果一出来就处理它们,你可以在每个任务上附加一个ContinueWith
。我不知道为什么,但当我这样做时,结果跟踪面板上没有添加任何内容。在函数resultStackPanel.Children.Count的末尾,值为0。不幸的是,我不能使用WhenAll,因为我想在结果一到就打印出来。如果你不需要所有任务,只需要第一个完成的任务,你可以使用Task。whenay
。问题是,当我在文本框中键入“test”之类的内容时,处理程序会执行4次,我只需要上次跑步的结果。我假设eventhandler可以同时执行多次,我认为这会导致等待调用出现问题,因为这些调用从未完成。如果您只需要最后一次运行。。这意味着你需要等待所有的人完成之前,以及。这意味着你需要等待所有的人。但是,只有当用户在一段时间内(比如200毫秒)没有键入时,才会触发事件的延迟。但这是一个新主题中的新问题。超时有效,但如果我想添加一个需要1秒计算结果的模块,该怎么办?然后我必须将超时设置为1秒,然后程序的责任就不好了。是否async/await不适用于此,我必须使用真正的并行性?我不知道为什么,但当我这样做时,结果跟踪面板中没有添加任何内容。在函数resultStackPanel.Children.Count的末尾,值为0。不幸的是,我不能使用WhenAll,因为我想在结果一到就打印出来。如果你不需要所有的任务,只需要第一个完成的任务,你可以使用Task。whenay
。问题是,当我在文本框中键入“test”之类的内容时,处理程序会执行4次,而我只需要任务的结果