2

私はツリー構造を持って、そのために私はこのクラスを使用しています:「」再帰的メソッドで並列処理を実装する方法は?

class Node 
{ 
    long IdNode; 
    List<Node> Childs; 
    string path; 
    Data data; 
} 

をパスすることによってspearated IdNodeので、ノードのパスはように 『IdParent.IdNode』です。したがって、ノードのパスを設定するには、親のパスが必要です。

私はこの方法を持っている:

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

    foreach(Node iteratorNode in this.Childs) 
    { 
     iteratorNode.setPath(this); 
    } 
} 

これはsecuentialバージョンです。しかし、私は、並行してそのような何かこれを実装する方法を考えていた:

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

    Parallel.Foreach(this.Childs, 
    (iteratorNode) => 
     { 
      iteratorNode.SetPathMt(this); 
     } 
    ); 
} 

をしかし、この場合、私はメソッドの再帰呼び出しを待つ方法を知らないので、私は、正しい方法を知りません、再帰的な方法がいつ終了したのか、私はどのように知っているのですか?それはそれのマルチスレッド再帰的なメソッドを実装するための最良の方法だろう

ありがとうございました。

+3

そして、なぜそんなことを並列化するのですか? 2つの文字列をドットで連結すると、連続したバージョンでは時間がかかりませんか? – Evk

答えて

1

あなたの方法は

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); 
     } 
    ); 
} 

のようなパラレル方式のようにする必要があります。 thisを使用すると、そのクラスのインスタンスを意味します。これは、すべての再帰メソッドで同じままです。変更されるのは、このメソッドで渡されるパラメータだけです。

new ParallelOptions { MaxDegreeOfParallelism = 32 }この並列操作で使用される同時操作(スレッド)の数を32(必要な数にすることができます)または-1(使用可能なすべてのスレッド)に制限します。

+1

ここで並列処理はどこですか? – Evk

+0

@エヴァーク:それが起こっていた。 –

+0

'新しいParallelOptions {MaxDegreeOfParallelism = 32}、'(またはそれが妥当なもの)を追加したいかもしれません。しかし、実際には、この制限がParallel.ForEachへのすべての同時呼び出し、またはそれぞれの呼び出しに適用されるかどうかはわかりません。つまり、ツリーが1000レベル深い場合は、一度に多くのスレッドを実行できます。 –

0

なぜこの操作を並行して実行するのかわかりません。私はあなたには大きな利点を得るためには非常に大きな木が必要だと思います。しかし、どちらの方法には、次のコードは、あなたがそれらをspec'dとしてパスを構築し、完全な作業例です:

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 

注意すべきもう一つのオプションSequentialの例をとり、の代わりにAsParallel().ForAllに電話をかけます。通常、それはParallelクラスよりも大きなオーバーヘッドを表しますが、実際にパフォーマンスを心配している場合は、そのバリエーションはミックスに投げる価値があります。

関連する問題