2017-04-15 21 views
0

私はネットワーク拡散の研究で頂点のための軽量フレームワークをモデリングする次のコードを持っています。最初のプロトタイプは、Javaに翻訳されたPythonのフレームワークからのものでした。私が持っている問題は、このコードは10000頂点までのPythonバージョンよりもはるかに高速ですが、より多くの頂点(100,000+)では停止することになります。実際Pythonのバージョンは1.2分で実行されましたが、Javaのビルドは7分の実行後も戻っていませんでした。なぜ同じコードがより多くの頂点で分解されているのかわかりませんし、コードを修正するのに助けが必要です。参考のためJavaコードの実行時間の問題

import java.util.*; 

public class Vertex 
{ 
    private int id; 
    private HashMap<Integer, Double> connectedTo; 
    private int status; 

    public Vertex(int key) 
    { 
    this.id = key; 
    this.connectedTo = new HashMap<Integer, Double>(); 
    this.status = 0; 
    } 

    public void addNeighbour(int nbr, double weight) 
    { 
    this.connectedTo.put(nbr, weight); 
    } 

    public int getId() 
    { 
    return this.id; 
    } 

    public double getWeight(int nbr) 
    { 
    return this.connectedTo.get(nbr); 
    } 

    public int getStatus() 
    { 
    return this.status; 
    } 

    public Set<Integer> getConnections() 
    { 
    return this.connectedTo.keySet(); 
    } 

//testing the class 

    public static void main(String[] args) 
    { 
    int noOfVertices = 100000; 

    Vertex[] vertexList = new Vertex[noOfVertices]; 

    for (int i = 0; i < noOfVertices; i++) { 
     vertexList[i] = new Vertex(i); 
    } 

    for (Vertex v : vertexList) { 
     int degree = (int)(500*Math.random()); //random choice of degree 
     int neighbourCount = 0; // count number of neighbours built up 

     while (neighbourCount <= degree) { 
      int nbr = (int) (noOfVertices * Math.random()); // randomly choose a neighbour 
      double weight = Math.random(); // randomly assign a weight for the relationship 
      v.addNeighbour(nbr, weight); 
      neighbourCount++; 
     } 
    } 

    } 
} 

、次のようにこのコードのPythonのバージョンは次のとおりです。

import random 

class Vertex: 
    def __init__(self, key): 
     self.id = key 
     self.connectedTo = {} 

    def addNeighbor(self, nbr, weight=0): 
     self.connectedTo[nbr] = weight 

    def __str__(self): 
     return str(self.id) + ' connectedTo: ' \ 
      + str([x.id for x in self.connectedTo]) 

    def getConnections(self): 
     return self.connectedTo.keys() 

    def getId(self): 
     return self.id 

    def getWeight(self, nbr): 
     return self.connectedTo[nbr] 

if __name__ == '__main__': 
    numberOfVertices = 100000 
    vertexList = [Vertex(i) for i in range(numberOfVertices)] # list of vertices 

    for vertex in vertexList: 
    degree = 500*random.random() 
    # build up neighbors one by one 
    neighbourCount = 0 

    while neighbourCount <= degree: 
     neighbour = random.choice(range(numberOfVertices)) 
     weight = random.random() # random choice of weight 
     vertex.addNeighbor(neighbour, weight) 
     neighbourCount = neighbourCount + 1 
+0

私は現在これを検討しており、すぐに最適化されたコードをいくつか掲載する予定です。 –

+0

プロファイリングなしで言うのは簡単ではなく、実際にはほとんどどこでもかまいません。ちょっとしたことですが、 'nextInt(bound)'メソッドを持つ 'java.util.Random'クラスを見てみましょう。(これは大したスピードアップではありません。 –

+0

解決策を見つけて下に投稿しました! –

答えて

0

これは非常に興味深い問題だった、と私は、私も何か新しいことを学んだと信じています。私は並列ストリームを利用するだけでなく、Randomよりも3倍速いThreadLocalRandomを使用するなど、さまざまな方法でコードを最適化しようとしました。しかし、私はついにJVMにメモリを割り当てたという主要なボトルネックを発見しました。

Mapには非常に多くの要素が追加されています(最悪の場合、頂点が100,000の500,000です)ので、多くのメモリ(ヒープスペース)が必要になります。 JVMがメモリを動的に割り当てることを許可すると、プログラムの実行に非常に時間がかかります。私がこれを解決したのは、あなたのIDEや端末で実行できるプログラムの実行コンフィギュレーションへのVM引数として-Xms3Gを適用して、JVM(特に3 GB)にメモリを事前に割り当てることでした。

私も(それが私のためにわずか数秒で完了します)私は下記掲載する予定ビットをあなたのコードを最適化してきました

import java.util.*; 
import java.util.concurrent.*; 
import java.util.stream.*; 

public class Test { 

    private static final ThreadLocalRandom RANDOM = ThreadLocalRandom.current(); 

    public static void main(String[] args) { 
     int noOfVertices = 100_000; 

     Vertex[] vertexList = new Vertex[noOfVertices]; 

     IntStream.range(0, noOfVertices).parallel().forEachOrdered(i -> { 
      vertexList[i] = new Vertex(i); 

      int degree = (int) (500 * RANDOM.nextDouble()); // random choice of degree 

      for (int j = 0; j <= degree; j++) { 
       int nbr = (int) (noOfVertices * RANDOM.nextDouble()); // randomly choose a neighbor 

       vertexList[i].addNeighbour(nbr, RANDOM.nextDouble()); 
      } 
     }); 
    } 

} 

class Vertex { 

    private int id; 

    private Map<Integer, Double> connectedTo; 

    private int status; 

    public Vertex(int id) { 
     this.id = id; 

     this.connectedTo = new HashMap<>(500); 
    } 

    public void addNeighbour(int nbr, double weight) { 
     this.connectedTo.put(nbr, weight); 
    } 

    public int getId() { 
     return this.id; 
    } 

    public double getWeight(int nbr) { 
     return this.connectedTo.get(nbr); 
    } 

    public int getStatus() { 
     return this.status; 
    } 

    public Set<Integer> getConnections() { 
     return this.connectedTo.keySet(); 
    } 

} 

私はThreadLocalRandomを使用に関する明示的な結果のわからないんだけどあなたが望むのであれば、それをMath#randomに戻すことができます。

+0

かなり優雅な解決策、私が考慮しなかったもの。あなたの努力を感謝します。 – buzaku

+0

@buzakuよろしくお願いします。ヒープスペースの割り当てがパフォーマンスに影響を与えることは正直なところ分かりませんでしたが、問題は解決してうれしいです! –

関連する問題