java - 如何使用 Java Streams API 在两个相同维度的列表之间进行元素明智的乘法

标签 java list math java-stream vectorization

我有 2 个列表,例如:

List<Double> margins =  Arrays.asList(1.0,2.0,3.0,4.0,5.0);
List<Integer> quantity = Arrays.asList(1,2,3,4,5);

我想在它们之间进行元素明智的乘法,我知道我可以用标准的 for 循环来做到这一点,但我想知道我们是否可以通过 Stream API 通过使过程更快和资源更少来实现相同的目的?

类似于 Python ML 对 NumPy 数组所做的事情;他们不是制作 for 循环,而是向量化使其更快的东西。

最佳答案

Something like what Python ML does with numpy arrays; instead of making a for loop they vectorize the thing which makes it faster.

如果您对 Vectorization 感兴趣,那么 Stream API 不是您正在寻找的东西。

自 Java 16 以来,我们有 Vector API作为incubating feature (这意味着它不是 API 的最终状态,它用于测试和收集反馈,您不应该在生产中使用它)。

为了使用 Java 中的孵化功能,您需要做一些额外的工作以从导入的孵化模块中获取文件。

确保导入包 jdk.incubator.vector 中的类的方法之一是创建一个模块 以明确指定它需要此包.

考虑一个具有以下文件夹结构的简单测试项目:

- [src]
  - [main]
    - [java]
      - module-info.java
      - [vectorization.test]
        - Main.java
      - resources

// other things

module-info.java - 我们在这里请求 Vector API 的文件:

module vectorization.test {
    requires jdk.incubator.vector;
}

Main.java

package vectorization.test;

import jdk.incubator.vector.DoubleVector;
import jdk.incubator.vector.VectorSpecies;

import java.util.Arrays;

public class Main {
    
    public static void main(String[] args) {
        double[] margins = {1.0, 2.0, 3.0, 4.0, 5.0};
        double[] quantity = {1, 2, 3, 4, 5};
        double[] result = new double[margins.length];
    
        multiply(margins, quantity, result);
    
        System.out.println(Arrays.toString(result));
    }
    
    public static final VectorSpecies<Double> SPECIES = DoubleVector.SPECIES_PREFERRED;
    
    public static void multiply(double[] margins, double[] quantity, double[] result) {
        int i = 0;
        for (; i < SPECIES.loopBound(margins.length); i += SPECIES.length()) {
            DoubleVector marginsVector = DoubleVector.fromArray(SPECIES, margins, i);
            DoubleVector quantityVector = DoubleVector.fromArray(SPECIES, quantity, i);
            DoubleVector resultVector = marginsVector.mul(quantityVector);
            resultVector.intoArray(result, i);
        }
        for (; i < margins.length; i++) {
            result[i] = margins[i] * quantity[i];
        }
    }
}

输出:

[1.0, 4.0, 9.0, 16.0, 25.0]

有关 Vector API 的更多信息,请查看 JEP 426 .

说到流,它们并不比普通循环性能更高(如果是顺序流),事实上它们更慢,因为流需要创建额外的对象来执行迭代,进行变换,积累结果。这里没有魔法。

并行流可能更快,但它是一种应谨慎使用的工具,因为您也可能会得到相反的效果。你需要你的任务是可并行的,你的线程应该有空闲的 CPU 核心来完成这项工作,并且数据量应该是巨大的以使并行流的使用合理(并且仍然必须测量性能以确定它是否使你的情况有所不同)。

在 Java 中引入函数式编程功能的主要目标之一是提供一种简洁且易读的代码结构方式。

例如,如何使用 Arrays.setAll() 填充生成的产品数组:

Arrays.setAll(result, i -> margins[i] * quantity[i]);

关于java - 如何使用 Java Streams API 在两个相同维度的列表之间进行元素明智的乘法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73296071/

相关文章:

java - Jenkins 构建不会在应该失败的时候失败

python - 将整数列表转换为字符串列表

python - 为什么 Python 将列表作为元组进行匹配?

Haskell Hermite 多项式实现

optimization - 稀疏最小二乘回归工具

c++ - 找到最接近给定素数列表的因素的数字

java - 将 Java Initial 和 Maximum 内存设置为相同值的性能

java - Outlook 日历与 Java Web 服务的连接

java - 检测应用程序是否获得焦点(而不是窗口焦点)

python - 在列表中查找特定的子列表