多线程对象的创建要比单线程慢 [英] Multi threaded object creation slower then in a single thread

查看:98
本文介绍了多线程对象的创建要比单线程慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个基本的问题.当我创建1亿个哈希表时,如果我在单个内核上执行,则大约需要6秒钟(运行时=每个内核6秒钟).如果我在12个内核(我的机器有6个允许超线程的内核)上执行多线程,则大约需要10秒钟(运行时间=每个内核112秒).

I have what probably is a basic question. When I create 100 million Hashtables it takes approximately 6 seconds (runtime = 6 seconds per core) on my machine if I do it on a single core. If I do this multi-threaded on 12 cores (my machine has 6 cores that allow hyperthreading) it takes around 10 seconds (runtime = 112 seconds per core).

这是我使用的代码:

主要

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

我不明白为什么要在多个线程中同时创建对象,而每个线程要花更长的时间,而在一个线程中却要串行地创建对象,为什么花更长的时间.如果删除创建哈希表的行,此问题将消失.如果有人可以帮助我,我将非常感激.

I do not understand why creating the object simultaneously in multiple threads takes longer per thread then doing it in serial in only 1 thread. If I remove the line where I create the Hashtable this problem disappears. If anyone could help me with this I would be greatly thankful.

推荐答案

更新:此问题与错误报告,并已通过Java 1.7u40修复.而且Java 1.8从来都不是问题,因为Java 8具有完全不同的哈希表算法.

Update: This problem has an associated bug report and has been fixed with Java 1.7u40. And it was never an issue for Java 1.8 as Java 8 has an entirely different hash table algorithm.

由于您没有使用所创建的对象,因此可以优化操作.因此,您只需衡量创建线程的开销.当然,开销越大,启动的线程越多.

Since you are not using the created objects that operation will get optimized away. So you’re only measuring the overhead of creating threads. This is surely the more overhead the more threads you start.

我必须更正关于细节的答案,但我还不知道:HashtableHashMap类有些特殊之处.它们都在构造函数中调用sun.misc.Hashing.randomHashSeed(this).换句话说,它们的实例在构造期间逸出,这对内存可见性有影响.这意味着与ArrayList不同,它们的构造无法优化,并且由于该方法内部发生的事情(即同步),导致多线程构造的速度变慢.

I have to correct my answer regarding a detail, I didn’t know yet: there is something special with the classes Hashtable and HashMap. They both invoke sun.misc.Hashing.randomHashSeed(this) in the constructor. In other words, their instances escape during construction which has an impact on the memory visibility. This implies that their construction, unlike let’s say for an ArrayList, cannot optimized away, and multi-threaded construction slows down due to what happens inside that method (i.e. synchronization).

如前所述,这是这些类的特殊设置,当然还有这种实现(我的设置:1.7.0_13).对于普通的类,此类代码的构造时间直接变为零.

As said, that’s special to these classes and of course this implementation (my setup:1.7.0_13). For ordinary classes the construction time goes straight to zero for such code.

在这里,我添加了更复杂的基准代码.观察DO_HASH_MAP = trueDO_HASH_MAP = false之间的区别(当false它将创建一个ArrayList而不具有这种特殊行为).

Here I add a more sophisticated benchmark code. Watch the difference between DO_HASH_MAP = true and DO_HASH_MAP = false (when false it will create an ArrayList instead which has no such special behavior).

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

这篇关于多线程对象的创建要比单线程慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆