【问题标题】:Make IEnumerable method async使 IEnumerable 方法异步
【发布时间】:2014-10-30 20:56:13
【问题描述】:

我有以下节点:

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) 遍历树,这样如果第三个节点的名称为== "Foo",那么我就不必遍历整个树。 现在这种情况是真的
  2. 让方法TraverseTree 在单独的线程上运行,因为它可能需要很长时间才能找到。所以我猜TraverseTree方法应该带一个callBack参数?
  3. 最后,如果能够取消该操作,那就太好了。我还需要向该方法传递一个取消令牌吗?

这样做的正确方法是什么?

抱歉,我忘了说我使用的是 .Net Framework 4.0

【问题讨论】:

标签: c# multithreading callback cancellation


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

【讨论】:

    【解决方案2】:

    首先,我会像这样实现你的函数(注意使用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();
    

    【讨论】:

    • 我不知道谁投了反对票,但很高兴知道为什么。我会尽快尝试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-14
    • 1970-01-01
    • 2019-02-01
    • 1970-01-01
    • 2012-10-28
    • 2020-12-19
    相关资源
    最近更新 更多