Fork/Join点点滴滴之一ParallelArray Part1

最后一部分ParallelArray Examples[1]

Code snippets, provided by the community, that use the currently available version of jsr166y. Since the framework is still in flux, there is no guarantee that these examples will compile.

从前文中看,ParallelArray实际上是Package extra166y部分中的内容。这里列出其WIKI中例子 in 简单的因为英语和优美的中文。

起源[2]:

对于排序和搜索问题,fork-join 库提供了一种表示可以并行化的数据集操作的非常简单的途径:ParallelArray 类。其思路是:用 ParallelArray 表示一组结构上类似的数据项,用 ParallelArray 上的方法创建一个对分解数据的具体方法的描述。然后用该描述并行地执行数组操作(幕后使用的是 fork-join 框架)。这种方法支持声明性地指定数据选择、转换和后处理操作,允许框架计算出合理的并行执行计划,就像数据库系统允许用 SQL 指定数据操作并隐藏操作的实现机制一样。ParallelArray 的一些实现可用于不同的数据类型和大小,包括对象数组和各种原语组成的数组。

ParallelArray 支持以下基本操作:

 

  • 筛选:选择计算过程中包含的元素子集。在清单 2 中,筛选器由 withFilter() 方法指定。

  • 应用:将一个过程应用到每个选中的元素。清单 2 没有展示这个技术,但是 apply() 方法允许对每个选中元素执行一个操作。

  • 映射:将选中的元素转换为另一种形式(例如从元素中提取数据字段)。在本例中,这个转换由 withMapping() 方法执行,我们将 Student 转换为学生的 GPA。其结果是指定选择和映射结果的ParallelArray

  • 替换:将每个元素替换为由它派生的另一个元素,创建新的并行数组。此技术与映射类似,但是形成新的 ParallelArray,可以在其上执行进一步查询。替换的一种情况是排序,将元素替换为不同的元素,从而对其进行排序(内置的 sort() 方法可用于此操作)。另一种特殊情况是 cumulate() 方法,该方法根据指定的组合操作用累积值替换每个元素。替换操作也可用于组合多个ParallelArray,例如创建一个 ParallelArray,其元素为对并行数组 a 和 b 执行 a[i]+b[i] 操作得到的值。

  • 汇总:将所有值组合为一个值,例如计算总和、平均值、最小值或最大值。清单 2 中的示例使用了 max() 方法。预定义的汇总方法,例如 min()sum() 和 max(),是用更通用的 reduce() 构建的。

 

  1. Creating arrays
    k,忘了用中文,创建数组。以ParallelDoubleArray 为例,其他的诸如ParallelArray<T>和ParallelLongArray与之类似,不再列出。
    ForkJoinPool fje = ParallelArray.defaultExecutor();
    int size = 10;
    double array[] = new double[size];
    for (int i = 0; i < size; i++) {
        array[i] = i;
    }
    //创建空的ParallelArray数组
    ParallelDoubleArray pda = ParallelDoubleArray.createEmpty(size, fje);
    //基于输入矩阵的一个副本创建ParallelArray,如果修改该ParallelArray也不会改变输入数组的值
    ParallelDoubleArray pda = ParallelDoubleArray.createFromCopy(array, fje);
     
  2. 初始化
    主要有以下几种方法初始化并行数组(Parallel Array): 2.1 每个元素都赋值一个值
    pda.replaceWithValue(1.0);
      2.2 添加一个原生数据数组,或其他并行数组
    // 在并行数组末尾添加double[]数组
    double[] array = // 获得double[]
    pda.addAll(array);
    
    // 给定并行数组 'pda', 可创建与'pda'内容相同的新的并行数组 'other' ,但是这两个数组不想关联
    // with the same contents. However, the two arrays are not linked.
    ParallelDoubleArray other = ParallelDoubleArray.createFromCopy(pda.size, pda.getExecutor())
    other.addAll(pda);
     
  3. 修改数组内容
    同样,也有很多方式修改数组的内容。
    3.1 用累计值来替换
    该例子首先初始化并行矩阵各元素为1.0,然后使用cumulateSum方法进行动求和结果{1.0,2.0,3.0,4.0,……}
    pda.replaceWithValue(1.0);
    pda.cumulateSum();
    运行结束后,再调用cumulateSum()方法,就会得到{1.0,3.0,6.0,10.0,...} 
    pda.cumulateSum();
     
    3.2 用某个计算值代替
    生成器(Generators)是一种不需接受输入参数就会生成值的对象。Ops.DoubleGenerator,有一个op()方法,它能生成并行数组。当然,还有诸如CommonOps.doubleRandom(),CommonOps.doubleRandom(double bound)和CommonOps.doubleRandom(double least,double bound)等随机数生成器。
    // 用随机double数来代替pda中元素值
    pda.replaceWithGeneratedValue(CommonOps.doubleRandom(0, 100.0));
     3.3 由匹配的已有数值来代替
    映射是一种操作,它吃掉一个值,然后再产出量一个数值。(which consumes one value and outputs another value that is normally derived from the input.)因此,对并行数组进行映射操作会修改其内容。例如,给数组所有元素添加一定数值等。假设ParallelDoubleArray pda的值{1.0,3.0,6.0.10.0,...},下面操作会将其内容替换为{11.0,13.0,16.0.20.0,...}
    static class Adder implements Ops.DoubleOp {
        private final double addend;
        Adder(final double addend) {
            this.addend = addend;
        }
        @Override
        public double op(final double a) {
            return a + addend;
        }
    }
    
    double x = 10;
    pda.replaceWithMapping(new Adder(x));
     当然,映射也可接收两个参数:元素索引和当前值。下面代码将elementi 替换为 f(i)+elementi。
    double f(int i) { ... }
    
    ...
    
    pda.replaceWithMappedIndex(new Ops.IntAndDoubleToDouble() {
                @Override
                public double op(final int i, final double element_i) {
                    return f(i) + element_i;
                }
    });
     3.4 顺序设定个别值
    类似于基本数组,可单独为并行数组赋值。
    pda.set(0, x);
    pda.set(1, y);
    
    ...
    
    // 把非并行数据复制到并行数组
    Map<Integer, Double> values = // ... some Map
    for(Map.Entry<Integer, Double> e : values) {
    pda.set(e.getKey(), e.getValue());
     

  4. 组合
    假如您掌握了创建、初始化和修改数组,接下来我们看一下多个并行数组间的操作。给定两个ParallelArray实例a和b,对其进行相加和点乘操作。
    4.1 两个矩阵的点乘操作
    下面代码对两个矩阵进行点乘,然后返回新的矩阵。
    public ParallelDoubleArray dotProduct(final ParallelDoubleArray a, final ParallelDoubleArray b) {
            return a.withMapping(new Ops.BinaryDoubleOp() {
                @Override
                public double op(final double x, final double y) {
                    return x * y;
                }
            }, b).all();
        }
     这里,应用到Ops.BinaryDoubleOp,它有方法:
    public double op(double x, double y) 
     该方法用于执行元素相乘。withMapping方法返回ParallelDoubleArrayWithDoubleMapping对象,它类似于一个Future(java.util.concurrent.Future),它有创建ParallelDoubleArray的能力,但本身却不是ParallelDoubleArray对象,该能力通过all()方法实现,用于执行同步映射。
    如果您想执行点乘,而不是创建新的ParallelDoubleArray,您可使用replaceWithMapping:
    a.replaceWithMapping(new Ops.BinaryDoubleOp() {
                @Override
                public double op(final double x, final double y) {
                    return x * y;
                }
            }, b);
     注意到,匿名类Ops.BinaryDoubleOp是一样的,因此可抽取重用:
    private static final Ops.BinaryDoubleOp multiplier = new Ops.BinaryDoubleOp() {
                @Override
                public double op(final double x, final double y) {
                    return x * y;
                }
            };
    
    // 执行点乘操作,并返回一个新的ParallelDoubleArray对象:
    public ParallelDoubleArray dotProduct(final ParallelDoubleArray a, final ParallelDoubleArray b) {
            return a.withMapping(multiplier, b).all();
        }
    // 点乘替换
    a.replaceWithMapping(multiplier, b);
     边注:Ops.DoubleReducer是继承于有着冗长名字的Ops.BinaryDoubleOp的额外接口。它通常用于规约操作,类似于函数式编程中的flod操作。
    4.2 两个矩阵相加
    与点乘类似,矩阵相加能更简单些,因为不再需要创建Ops.BinaryDoubleOp对象来执行加法操作,而起本身已经提供了CommonOps类。
    public ParallelDoubleArray plus(final ParallelDoubleArray a, final ParallelDoubleArray b) {
            return a.withMapping(CommonOps.doubleAdder(), b).all();
        }
     或者替换:
    a.replaceWithMapping(CommonOps.doubleAdder(), b);

 

参考文献:

[1] jsr166y.forkjoin Examples.http://artisans-serverintellect-com.si-eioswww6.com/default.asp?W32 .

[2]Brian Goetz .用 Java 7 中的 ParallelArray 类加速排序和搜索. http://www.ibm.com/developerworks/cn/java/j-jtp03048.html .

你可能感兴趣的:(数据结构,sql,编程,框架,asp)