Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/283.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 多次执行异步eventhandler_C#_Wpf_Task Parallel Library_Async Await_Deadlock - Fatal编程技术网

C# 多次执行异步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 =

我有一个eventhandler,可以执行多次。当我让它完成执行时,一切正常(只键入一个字符,然后等待计算结果)。 但当我正常输入时,就会出现死锁。至少我认为这是一个僵局

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次,而我只需要任务的结果