Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.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# 如何用递归方法实现并行性?_C#_.net_Multithreading_Task Parallel Library_Parallel.foreach - Fatal编程技术网

C# 如何用递归方法实现并行性?

C# 如何用递归方法实现并行性?,c#,.net,multithreading,task-parallel-library,parallel.foreach,C#,.net,Multithreading,Task Parallel Library,Parallel.foreach,我有一个树结构,因此我使用这个类: class Node { long IdNode; List<Node> Childs; string path; Data data; } 这是一个非正式的版本。但我在想如何并行实现这一点,比如: public setPathMt(Node paramParentNode) { this.path = paramParentNode.Path + "." + this.IDNode; Paral

我有一个树结构,因此我使用这个类:

class Node
{
    long IdNode;
    List<Node> Childs;
    string path;
    Data data;
}
这是一个非正式的版本。但我在想如何并行实现这一点,比如:

public setPathMt(Node paramParentNode)
{
    this.path = paramParentNode.Path + "." + this.IDNode;

    Parallel.Foreach(this.Childs,
     (iteratorNode) =>
      {
          iteratorNode.SetPathMt(this);
      }
     );
}
但是我不知道这是否是正确的方法,因为我不知道如何等待方法的递归调用,我的意思是,我如何知道递归方法何时完成

实现这种多线程递归方法的最佳方法是什么


谢谢。

您的方法应该是

public SetPath(Node paramParentNode)
{
    paramParentNode.Path = paramParentNode.Path + "." + this.IDNode;

    foreach(Node iteratorNode in paramParentNode.Childs)
    {
        SetPath(iteratorNode);
    }
}
还有像这样的并行方法

public SetPathMt(Node paramParentNode)
{
    paramParentNode.Path = paramParentNode.Path + "." + this.IDNode;

    Parallel.Foreach(paramParentNode.Childs,
     new ParallelOptions { MaxDegreeOfParallelism = 32 },
     (iteratorNode) =>
      {
          SetPathMt(iteratorNode);
      }
     );
}
您根本没有使用在方法中传递的节点。当您使用
这个
时,它意味着该类的实例,它在所有递归方法中都保持不变。唯一改变的是方法中的参数传递


新的并行选项{MaxDegreeOfParallelism=32}
将此并行操作使用的并发操作(线程)数量限制为32(可以是您想要的数字)或-1(所有可用线程)。

不确定为什么要并行运行此操作。我认为你需要一棵很大的树才能获得任何优势。但无论哪种方式,下面的代码都是一个完整的工作示例,可以按照您指定的方式构建路径:

using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;

namespace ClassLibrary2 {

    [TestFixture]
    public class NodePathHandler {

        [Test]
        public void SetNodePathsTest() {
            var tree = new Node() {
                IdNode = 1,
                Childs = Enumerable.Range(1, 2).Select(nId1 => new Node() {
                    IdNode = 1 + nId1,
                    Childs = Enumerable.Range(1, 2).Select(nId2 => new Node() {
                        IdNode = nId1 + nId2,
                        Childs = Enumerable.Range(1, 2).Select(nId3 => new Node() {
                            IdNode = nId2 + nId3,
                            Childs = Enumerable.Empty<Node>().ToList()
                        }).ToList()
                    }).ToList()
                }).ToList()
            };
            var sw = Stopwatch.StartNew();
            SetNodePaths(tree);
            Console.WriteLine($"Time: {sw.ElapsedMilliseconds}ms");
        }

        public void SetNodePaths(Node node, string parentPath = null) {
            node.Path = parentPath == null ? node.IdNode.ToString() : $"{parentPath}.{node.IdNode}";            
            //Sequential
            //node.Childs.ForEach(n => SetNodePaths(n, node.Path));
            //Parallel
            Parallel.ForEach(node.Childs, n => SetNodePaths(n, node.Path));
            Console.WriteLine($"Node Id: {node.IdNode} Node Path: {node.Path}");
        }
    }

    public class Node {
        public long IdNode { get; set; }
        public List<Node> Childs { get; set; }
        public string Path { get; set; }
        public Data Data { get; set; }
    }

    public class Data { }
}

另一个需要注意的选项是以
Sequential
为例,添加对
aspallel()的调用。ForAll
而不是
ForEach
。通常这比
Parallel
类的开销更大,但是如果你真的关心性能的话,那么这个变量是值得一试的。

这里的并行性在哪里?@Evk:接下来就是了。你可能想添加
新的并行选项{MaxDegreeOfParallelism=32},
(或者任何合理的东西)。但事实上,我甚至不确定这个限制是否适用于对Parallel.ForEach的所有同时调用,或者仅适用于每个调用,这意味着如果树有1000层深,那么可以同时运行许多线程。@DylanNicholson:当然可以。这将限制要运行的并行线程的数量。谢谢你指出这一点。更新了我的答案。这在逻辑上似乎不正确。首先,
this.IDNode
始终是相同的,因此将相同的字符串附加到所有路径(无递归路径构建)。第二,
paramParentNode
应该是父节点,并且在那里传递子节点。为什么要并行化这样的事情呢?在顺序版本中,将2个字符串与一个点连接应该不会花费太多时间?
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;

namespace ClassLibrary2 {

    [TestFixture]
    public class NodePathHandler {

        [Test]
        public void SetNodePathsTest() {
            var tree = new Node() {
                IdNode = 1,
                Childs = Enumerable.Range(1, 2).Select(nId1 => new Node() {
                    IdNode = 1 + nId1,
                    Childs = Enumerable.Range(1, 2).Select(nId2 => new Node() {
                        IdNode = nId1 + nId2,
                        Childs = Enumerable.Range(1, 2).Select(nId3 => new Node() {
                            IdNode = nId2 + nId3,
                            Childs = Enumerable.Empty<Node>().ToList()
                        }).ToList()
                    }).ToList()
                }).ToList()
            };
            var sw = Stopwatch.StartNew();
            SetNodePaths(tree);
            Console.WriteLine($"Time: {sw.ElapsedMilliseconds}ms");
        }

        public void SetNodePaths(Node node, string parentPath = null) {
            node.Path = parentPath == null ? node.IdNode.ToString() : $"{parentPath}.{node.IdNode}";            
            //Sequential
            //node.Childs.ForEach(n => SetNodePaths(n, node.Path));
            //Parallel
            Parallel.ForEach(node.Childs, n => SetNodePaths(n, node.Path));
            Console.WriteLine($"Node Id: {node.IdNode} Node Path: {node.Path}");
        }
    }

    public class Node {
        public long IdNode { get; set; }
        public List<Node> Childs { get; set; }
        public string Path { get; set; }
        public Data Data { get; set; }
    }

    public class Data { }
}
Node Id: 2 Node Path: 1.2.2.2
Node Id: 3 Node Path: 1.2.2.3
Node Id: 2 Node Path: 1.2.2
Node Id: 3 Node Path: 1.2.3.3
Node Id: 2 Node Path: 1.3.3.2
Node Id: 3 Node Path: 1.3.4.3
Node Id: 3 Node Path: 1.3.3.3
Node Id: 3 Node Path: 1.3.3
Node Id: 4 Node Path: 1.2.3.4
Node Id: 4 Node Path: 1.3.4.4
Node Id: 4 Node Path: 1.3.4
Node Id: 3 Node Path: 1.2.3
Node Id: 3 Node Path: 1.3
Node Id: 2 Node Path: 1.2
Node Id: 1 Node Path: 1
Time: 4ms