Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 8流矩阵乘法比For循环慢10倍?_Java_Math_Java 8_Benchmarking_Java Stream - Fatal编程技术网

Java 8流矩阵乘法比For循环慢10倍?

Java 8流矩阵乘法比For循环慢10倍?,java,math,java-8,benchmarking,java-stream,Java,Math,Java 8,Benchmarking,Java Stream,我创建了一个使用流执行矩阵乘法的模块。可以在这里找到: 我试图编写一个基准测试,以便将流循环实现与Apache Commons Math中相应的for循环实现进行比较 基准模块如下所示: 这里的实际基准是: 当我在大小为100X100和1000X1000的矩阵上运行基准测试时,结果表明Apache Commons Math(使用for循环)比相应的流实现快10倍(大致) # Run complete. Total time: 00:14:10 Benchmark

我创建了一个使用流执行矩阵乘法的模块。可以在这里找到:

我试图编写一个基准测试,以便将流循环实现与Apache Commons Math中相应的for循环实现进行比较

基准模块如下所示:

这里的实际基准是:

当我在大小为100X100和1000X1000的矩阵上运行基准测试时,结果表明Apache Commons Math(使用for循环)比相应的流实现快10倍(大致)

# Run complete. Total time: 00:14:10

Benchmark                              Mode  Cnt      Score     Error      Units
MultiplyBenchmark.multiplyCM1000_1000  avgt   30   1040.804 ±  11.796  ms/op
MultiplyBenchmark.multiplyCM100_100    avgt   30      0.790 ±   0.010  ms/op
MultiplyBenchmark.multiplyFM1000_1000  avgt   30  11981.228 ± 405.812  ms/op
MultiplyBenchmark.multiplyFM100_100    avgt   30      7.224 ±   0.685  ms/op
我在基准测试中是否做错了什么(希望:)

我添加了经过测试的方法,这样每个人都可以看到正在比较的内容。这是Apache Commons Math Array2DroArralMatrix.multiply()方法:

/**
*返回将{@code this}乘以{@code m}后的结果。
*
*@param m m矩阵通过后乘
*@return{@code this*m}
*@抛出维度不匹配异常,如果
*{@code columnDimension(this)!=行维度(m)}
*/
公共ARRAY2DROREALMATRIX乘法(最终ARRAY2DROREALMATRIX m)
抛出维度不匹配异常{
MatrixUtils.checkMultiplicationCompatible(this,m);
final int nRows=this.getRowDimension();
final int nCols=m.getColumnDimension();
final int nSum=this.getColumnDimension();
最终双精度[][]输出数据=新双精度[nRows][nCols];
//将包含一列“m”。
最终双精度[]mCol=新双精度[nSum];
最终双精度[][]mData=m.data;
//倍增。
for(int col=0;col
这是相应的流实现:

/**
 * Returns a {@link BinaryOperator} that multiplies {@link SimpleMatrix}
 * {@code m1} times {@link SimpleMatrix} {@code m2} (m1 X m2).
 * 
 * Example {@code multiply(true).apply(m1, m2);}
 * 
 * @param parallel
 *            Whether to perform the operation concurrently.
 * 
 * @throws MathException
 *             Of type {@code MATRIX_DIMENSION_MISMATCH__MULTIPLICATION} if
 *             {@code m} is not the same size as {@code this}.
 * 
 * @return the {@link BinaryOperator} that performs the operation.
 */
public static BinaryOperator<SimpleMatrix> multiply(boolean parallel) {

    return (m1, m2) -> {
        checkMultiplicationCompatible(m1, m2);

        double[][] a1 = m1.toArray();
        double[][] a2 = m2.toArray();

        Stream<double[]> stream = Arrays.stream(a1);
        stream = parallel ? stream.parallel() : stream;

        final double[][] result =
                stream.map(r -> range(0, a2[0].length)
                        .mapToDouble(i -> range(0, a2.length).mapToDouble(j -> r[j]
                                * a2[j][i]).sum())
                        .toArray()).toArray(double[][]::new);

        return new SimpleMatrix(result);
    };
}
/**
*返回一个{@link BinaryOperator}乘以{@link SimpleMatrix}
*{@code m1}乘以{@link SimpleMatrix}{@code m2}(m1×m2)。
* 
*示例{@code multiply(true).apply(m1,m2);}
* 
*@param并行
*是否同时执行该操作。
* 
*@抛出异常
*类型{@code MATRIX\u DIMENSION\u MISMATCH\u乘法}如果
*{@code m}与{@code this}的大小不同。
* 
*@return执行该操作的{@link BinaryOperator}。
*/
公共静态二进制运算符乘法(布尔并行){
返回(m1,m2)->{
checkMultiplicationCompatible(m1,m2);
double[]a1=m1.toArray();
double[]a2=m2.toArray();
Stream=Arrays.Stream(a1);
stream=parallel?stream.parallel():stream;
最终双[][]结果=
stream.map(r->range(0,a2[0].长度)
.maptouble(i->range(0,a2.长度).maptouble(j->r[j]
*a2[j][i]).sum())
.toArray()).toArray(双[]]::新建);
返回新的SimpleMatrix(结果);
};
}
蒂亚,
Ole

查看一下双管道。toArray

public final double[] toArray() {
  return Nodes.flattenDouble((Node.OfDouble) evaluateToArrayNode(Double[]::new))
                    .asPrimitiveArray();
}

似乎首先创建一个装箱数组,然后将其转换为一个基本数组。

@Holger
toArray
是一个简单的字段访问器。我明白了。我的猜测是数据局部性和缓存未命中-可能还有更多…我发现结果仍然很奇怪。只要有可能,我会尽快运行该基准测试。@assylias:
DoubleStream.sum()
使用的错误补偿算法可能比简单的求和循环更昂贵。然而,我并不期望因子10。关于局部性,与Apache的数学库不同,您的循环变量对提高数据局部性没有任何作用。@Holger发现得很好-不使用
DoubleStream::sum
将性能提高了30%-现在比率为“仅”与原始版本相比,速度慢了6倍,慢了8倍。@assylias:通过将数组长度读入局部变量,可以获得更多的百分比,就像在循环变量中一样,也可以
a2
(与lambda实例通过捕获的
this
实例重新读取字段相比,hotspot更容易消除循环变量中对
a2
字段的不必要的重新读取)。似乎此函数仅用于实现内部接口(或者可能在调用
boxed()
时使用)。在执行逐步调试时,您将看到此生成器未在本例中使用。返回的节点将包含一个
double[]
数组,并且由于此流具有固定大小,
asPrimitiveArray()
将直接返回它。@霍尔格感谢您的更新。如果答案错误,我将查看它并删除它。可能是由于当时创建了大量流造成的。答案实际上是不正确的。之后不再使用此生成器。它已通过
AP::evaluateToaryNode
->
AP::evaluate->
DP::makeNodeBuilder
在这里它被忽略。
public final double[] toArray() {
  return Nodes.flattenDouble((Node.OfDouble) evaluateToArrayNode(Double[]::new))
                    .asPrimitiveArray();
}