取消Parallel.ForEach或使用async等待

时间:2014-07-29 13:59:54

标签: c# asynchronous parallel.foreach async-await

我有这个事件:

private void  TextBoxSearchText_TextChanged(object sender, TextChangedEventArgs e)
{
    searchText();
}

我希望取消这个并行方法并在文本框文本更改时启动一个新方法,并且还希望我的文本框能够响应我的新文本输入,这将锁定直到结果出现在列表框中。

List<TextList> oSelected;
private void searchText()
{
string strSearchText = TextBoxSearchText.Text;
    oSelected = new List<TextList>();            
    Parallel.ForEach(oTextList, item  =>
    {
        Match myMatch = Regex.Match(item.EnglishText.ToString(), "\\b" + strSearchText.ToString().ToLower() + @"\w*", RegexOptions.IgnoreCase);
        if (!myMatch.Success)
        {
            return;
        }

        oSelected.Add(new TextList
        {
            Id = item.Id,
            EnglishText = item.EnglishText
        });
    });

    ListBoxAllTexts.ItemsSource = oSelected;
}

是否可以使用async和awiat来完成这项工作? 哪一个更适合在近100万行文本中搜索文本? 我读了很多关于异步和等待但我无法理解如何在我的工作中使用它。 谢谢

1 个答案:

答案 0 :(得分:5)

由于您的工作受CPU限制,因此您应该使用并行代码进行实际搜索。但是,您可以使用asyncawait / Task.Run构思包装并行工作:

private async void TextBoxSearchText_TextChanged(object sender, TextChangedEventArgs e)
{
  ListBoxAllTexts.ItemsSource = await Task.Run(() => searchText(TextBoxSearchText.Text));
}

这将使您的UI保持响应。

要取消,use a CancellationTokenSource。另外,您不能像平行循环一样更新List<T>,因为List<T>不是线程安全的。在这种情况下,我建议您使用PLINQ:

private CancellationTokenSource _cts;
private async void TextBoxSearchText_TextChanged(object sender, TextChangedEventArgs e)
{
  if (_cts != null)
    _cts.Cancel();
  _cts = new CancellationTokenSource();
  var strSearchText = TextBoxSearchText.Text;
  ListBoxAllTexts.ItemsSource = await Task.Run(
      () => searchText(strSearchText, _cts.Token));
}

private List<TextList> searchText(string strSearchText, CancellationToken token)
{
  try
  {
    return oTextList.AsParallel().WithCancellation(token)
        .Where(item => Regex.IsMatch(item.EnglishText.ToString(), "\\b" + strSearchText.ToLower() + @"\w*", RegexOptions.IgnoreCase))
        .Select(item => new TextList
        {
          Id = item.Id,
          EnglishText = item.EnglishText
        })
        .ToList();
  }
  catch (OperationCanceledException)
  {
    return null;
  }
}

此外,请考虑通过仅在延迟后开始搜索来限制用户输入。 Rx是最好的方法。