使IEnumerable方法异步

本文关键字:异步 方法 IEnumerable | 更新日期: 2023-09-27 18:28:27

我有以下节点:

class Node
{
    public string Name;        
    public IEnumerable<Node> Children;
}

我有以下扩展方法:

public static class ExtensionMethods
{
    public static IEnumerable<Node> TraverseTree(this Node root)
    {
        if (root.Children != null)
        {
            foreach (var child in root.Children)
            {
                var nodes = TraverseTree(child);
                foreach (var node in nodes)
                {
                    yield return node;
                }
            }
        }
        yield return root;
    }       
}

我想在树中搜索一个名为"Foo"的节点。为了做到这一点,我做了:

Node myNode = /* some large tree! */
var search = myNode.TraverseTree().Where(x=>x.Name == "Foo").FirstOrDefault();

我有3个目标

  1. 让方法TraverseTree以yield(IEnumerable)遍历树,这样,如果第3个节点恰好具有name="Foo",那么我就不必遍历整个树现在这种情况是真的
  2. 使方法TraverseTree在单独的线程上运行,因为它可能需要很长时间才能找到。因此,我认为TraverseTree方法应该采用回调参数
  3. 最后,能够取消该操作将是一件好事。我是否也需要向该方法传递一个取消令牌

正确的方法是什么?

对不起,我忘了提到我正在使用.Net Framework 4.0

使IEnumerable方法异步

  1. 这已经用您的代码完成了。赞成延期执行
  2. 到目前为止,更简单的方法是保持方法同步,并将整个查询移动到另一个线程中
  3. 是的,您当然可以添加一个由遍历算法、子选择器或两者都检查的CancellationToken。另一种选择是让等待遍历结果的任何东西停止等待,而不是试图实际停止计算

首先,我会这样实现您的函数(注意CancellationToken的使用)

public static IEnumerable<Node> TraverseTree(this Node root, CancellationToken token)
{
    if (root.Children != null)
    {
        foreach (var child in root.Children)
        {
            if (token.IsCancellationRequested) return; //cancel if requested.
            var nodes = TraverseTree(child);
            foreach (var node in nodes)
            {
                yield return node;
                if (token.IsCancellationRequested) return; //cancel if requested.
            }
        }
    }
    yield return root;
}     

然后,以下是呼叫的样子:

var cts = new CancellationTokenSource();
var task = Task.Run(
    () => myNode.TraverseTree(cts.Token).Where(x=>x.Name == "Foo").FirstOrDefault(),
    cts.Token);

稍后,如果你想取消,你只需拨打:

cts.Cancel();