-1

おそらく基本的な質問があります。1 億個の Hashtable を作成する場合、シングル コアで作成した場合、私のマシンでは約 6 秒 (ランタイム = コアあたり 6 秒) かかります。これを 12 コアでマルチスレッド化すると (私のマシンにはハイパースレッディングが可能な 6 つのコアがあります)、約 10 秒かかります (ランタイム = コアあたり 112 秒)。

これは私が使用するコードです:

主要

public class Tests 
{
public static void main(String args[])
{
    double start = System.currentTimeMillis();
    int nThreads = 12;
    double[] runTime = new double[nThreads];

    TestsThread[] threads = new TestsThread[nThreads];
    int totalJob = 100000000;
    int jobsize = totalJob/nThreads;
    for(int i = 0; i < threads.length; i++)
    {
        threads[i] = new TestsThread(jobsize,runTime, i);
        threads[i].start();
    }
    waitThreads(threads);
    for(int i = 0; i < runTime.length; i++)
    {
        System.out.println("Runtime thread:" + i + " = " + (runTime[i]/1000000) + "ms");
    }
    double end = System.currentTimeMillis();
    System.out.println("Total runtime = " + (end-start) + " ms");
}

private static void waitThreads(TestsThread[] threads) 
{
    for(int i = 0; i < threads.length; i++)
    {
        while(threads[i].finished == false)//keep waiting untill the thread is done
        {
            //System.out.println("waiting on thread:" + i);
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }   
}
}

スレッド

import java.util.HashMap;
import java.util.Map;

public class TestsThread extends Thread
{
int jobSize = 0;
double[] runTime;
boolean finished;
int threadNumber;

TestsThread(int job, double[] runTime, int threadNumber)
{
    this.finished = false;
    this.jobSize = job;
    this.runTime = runTime;
    this.threadNumber = threadNumber;
}

public void run()
{
    double start = System.nanoTime();
    for(int l = 0; l < jobSize ; l++)
    {   
         double[] test = new double[65];
    }
    double end = System.nanoTime();
    double difference = end-start;
    runTime[threadNumber] += difference;
    this.finished = true;
}
}

複数のスレッドでオブジェクトを同時に作成すると、スレッドごとに時間がかかり、1 つのスレッドでシリアルに作成するよりも時間がかかる理由がわかりません。Hashtable を作成する行を削除すると、この問題はなくなります。誰かがこれで私を助けることができれば、私は非常に感謝しています.

4

3 に答える 3

1

更新: この問題には関連するバグ レポートがあり、 で修正されていJava 1.7u40ます。Java 1.8また、Java 8 にはまったく異なるハッシュ テーブル アルゴリズムがあるため、これが問題になることはありませんでした。


作成されたオブジェクトを使用していないため、その操作は最適化されなくなります。したがって、スレッド作成のオーバーヘッドのみを測定しています。これは確かに、開始するスレッドが多いほどオーバーヘッドが大きくなります。

詳細についての回答を修正する必要がありますが、まだ知りませんでした。クラスHashtableとには何か特別なものがありHashMapます。sun.misc.Hashing.randomHashSeed(this)どちらもコンストラクターで呼び出します。つまり、それらのインスタンスは構築中にエスケープされ、メモリの可視性に影響を与えます。これは、 の場合とは異なり、それらの構築をArrayList最適化して取り除くことができず、そのメソッド内で発生すること (つまり、同期) によりマルチスレッド構築が遅くなることを意味します。

前述のように、これはこれらのクラスと、もちろんこの実装 (私のセットアップ: 1.7.0_13) にとって特別なものです。通常のクラスの場合、そのようなコードの構築時間はゼロになります。

ここでは、より洗練されたベンチマーク コードを追加します。と の違いに注意してDO_HASH_MAP = trueくださいDO_HASH_MAP = false(そのような特別な動作を持たない代わりにfalseが作成される場合)。ArrayList

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

public class AllocBench {
  static final int NUM_THREADS = 1;
  static final int NUM_OBJECTS = 100000000 / NUM_THREADS;
  static final boolean DO_HASH_MAP = true;

  public static void main(String[] args) throws InterruptedException, ExecutionException {
    ExecutorService threadPool = Executors.newFixedThreadPool(NUM_THREADS);
    Callable<Long> task=new Callable<Long>() {
      public Long call() {
        return doAllocation(NUM_OBJECTS);
      }
    };

    long startTime=System.nanoTime(), cpuTime=0;
    for(Future<Long> f: threadPool.invokeAll(Collections.nCopies(NUM_THREADS, task))) {
      cpuTime+=f.get();
    }
    long time=System.nanoTime()-startTime;
    System.out.println("Number of threads: "+NUM_THREADS);
    System.out.printf("entire allocation required %.03f s%n", time*1e-9);
    System.out.printf("time x numThreads %.03f s%n", time*1e-9*NUM_THREADS);
    System.out.printf("real accumulated cpu time %.03f s%n", cpuTime*1e-9);

    threadPool.shutdown();
  }

  static long doAllocation(int numObjects) {
    long t0=System.nanoTime();
    for(int i=0; i<numObjects; i++)
      if(DO_HASH_MAP) new HashMap<Object, Object>(); else new ArrayList<Object>();
    return System.nanoTime()-t0;
  }
}
于 2013-09-13T12:53:03.510 に答える
0

6コアでやるとどうなる?ハイパースレッディングは、コアを 2 倍にすることとまったく同じではないため、実際のコアの量も試してみることをお勧めします。

また、OS は必ずしも各スレッドを独自のコアにスケジュールするとは限りません。

于 2013-09-13T12:50:15.280 に答える