Java 数据库基准测试:测试并发性时的奇怪结果(ExecutorService)

Java 数据库基准测试:测试并发性时的奇怪结果(ExecutorService),java,concurrency,benchmarking,derby,Java,Concurrency,Benchmarking,Derby,我目前正在开发一个java基准,用ApacheDerby数据库评估一些用例(插入、更新、删除等) 我的实施如下: 在预热JVM之后,我在数据库的一个表中执行一系列(for循环:(100k到1M次迭代)),比如说,ÌNSERT。由于这是一个ApacheDerby,对于那些知道的人,我测试了每种模式(内存/嵌入式、内存/网络、持久/嵌入式、持久/网络) 进程的执行可以是单线程的,也可以是多线程的(使用Executors.newFixedThreadPool(poolSize) 好吧,我的问题来了:

我目前正在开发一个java基准,用ApacheDerby数据库评估一些用例(插入、更新、删除等)

我的实施如下:

在预热JVM之后,我在数据库的一个表中执行一系列(for循环:(100k到1M次迭代)),比如说,
ÌNSERT
。由于这是一个ApacheDerby,对于那些知道的人,我测试了每种模式(内存/嵌入式、内存/网络、持久/嵌入式、持久/网络)

进程的执行可以是单线程的,也可以是多线程的(使用
Executors.newFixedThreadPool(poolSize)

好吧,我的问题来了:

当我只使用1个线程执行基准测试时,我得到了非常真实的结果

内存中/嵌入式[简单整数插入]:35K插入/秒(1线程)

然后,我决定依次执行1个线程和2个(并发)线程

现在,我有以下结果:

In memory/embedded[Simple Integer Insert] : 21K inserts/second (1 thread)
In memory/embedded[Simple Integer Insert] : 20K inserts/second (2 thread)
为什么一个线程的结果变化这么大

基本上,我在循环前后启动和结束计时器:

// Processing
long start = System.nanoTime();

for (int i = 0; i < loopSize; i++) {
    process();
}
// end timer
long absTime = System.nanoTime() - start;
double absTimeMilli = absTime * 1e-6;
由于执行是按顺序处理的,代码的剩余部分(数据处理)不应该改变基准

随着顺序线程数量的增加,结果会变得更糟(例如,1、2、4、8)

如果这让人困惑,我很抱歉。如果需要,我会提供更多信息或重新解释

谢谢你的帮助:)

编辑:

以下是调用上述执行的方法(来自Usecase类):

@Override
public ArrayList<ContextBean> bench(int loopSize, int poolSize) throws InterruptedException, ExecutionException {
    Future<ContextBean> t = null;
    ArrayList<ContextBean> cbl = new ArrayList<ContextBean>();

    try {

        ExecutorService es = Executors.newFixedThreadPool(poolSize);


        for (int i = 0; i < poolSize; i++) {
            BenchExecutor be = new BenchExecutor(eds, insertStatement, loopSize, poolSize, "test-varchar");
            t = es.submit(be); 
            cbl.add(t.get());
        }

        es.shutdown();
        es.awaitTermination(Long.MAX_VALUE,TimeUnit.MILLISECONDS);

    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return cbl;
}
@覆盖
公共ArrayList工作台(int loopSize,int poolSize)引发InterruptedException、ExecutionException{
未来t=null;
ArrayList cbl=新的ArrayList();
试一试{
ExecutorService es=Executors.newFixedThreadPool(池大小);
对于(int i=0;i
在简单操作中,每个数据库的行为都与您描述的一样

原因是生成的所有线程都试图在同一个表(或一组表)上操作,因此数据库必须序列化访问

在这种情况下,每个线程都会稍微慢一点,但总体结果是(小)增益。(与单螺纹版本的35K相比,21K+20K=41K)

增益随着线程数的增加而减少(通常是指数级的),最终可能会由于锁升级而丢失(请参阅)


通常,当多线程解决方案的性能不受单个资源的约束,而是受多个因素(即计算、在多个表上选择、在不同表上插入)的约束时,多线程解决方案的收益最大

在简单操作中,每个数据库的行为都与您描述的一样

原因是生成的所有线程都试图在同一个表(或一组表)上操作,因此数据库必须序列化访问

在这种情况下,每个线程都会稍微慢一点,但总体结果是(小)增益。(与单螺纹版本的35K相比,21K+20K=41K)

增益随着线程数的增加而减少(通常是指数级的),最终可能会由于锁升级而丢失(请参阅)


通常,当多线程解决方案的性能不受单个资源的约束,而是受多个因素(即计算、在多个表上选择、在不同表上插入)的约束时,多线程解决方案的收益最大

谢谢你的回答!因此,addind结果应该没有意义,因为如果我使用1个线程或1个线程执行我的工作台,然后使用2个线程(分别执行),我将获得类似于[1个线程:30-35K,2个线程:20-25K]的结果,或者我缺少了什么:-/?事实上,它们在同一个表上运行,这可能是原因所在。事实上,每次执行后,我都会删除并重新创建该表。同样,这应该被视为每次执行的一个新的开始:
BenchExecutor
code和
insertStatement
查询可能有助于更好地猜测数据库端的并发性问题。感谢您的回答!因此,addind结果应该没有意义,因为如果我使用1个线程或1个线程执行我的工作台,然后使用2个线程(分别执行),我将获得类似于[1个线程:30-35K,2个线程:20-25K]的结果,或者我缺少了什么:-/?事实上,它们在同一个表上运行,这可能是原因所在。事实上,每次执行后,我都会删除并重新创建该表。再一次,这应该被视为每次执行的一个新的开始:
BenchExecutor
code和
insertStatement
查询可能有助于更好地猜测数据库端的并发性问题。
@Override
public ArrayList<ContextBean> bench(int loopSize, int poolSize) throws InterruptedException, ExecutionException {
    Future<ContextBean> t = null;
    ArrayList<ContextBean> cbl = new ArrayList<ContextBean>();

    try {

        ExecutorService es = Executors.newFixedThreadPool(poolSize);


        for (int i = 0; i < poolSize; i++) {
            BenchExecutor be = new BenchExecutor(eds, insertStatement, loopSize, poolSize, "test-varchar");
            t = es.submit(be); 
            cbl.add(t.get());
        }

        es.shutdown();
        es.awaitTermination(Long.MAX_VALUE,TimeUnit.MILLISECONDS);

    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return cbl;
}