合规国际互联网加速 OSASE为企业客户提供高速稳定SD-WAN国际加速解决方案。 广告
## 数组并行 我们很快就不得不面对并行的主题。例如,“并行”一词在许多Java库方法中使用。您可能听说过类似“并行程序运行得更快”这样的说法,这是有道理的—当您可以有多个处理器时,为什么只有一个处理器在您的程序上工作呢? 如果您认为您应该利用其中的“并行”,这是很容易被原谅的。 要是这么简单就好了。不幸的是,通过采用这种方法,您可以很容易地编写比非并行版本运行速度更慢的代码。在你深刻理解所有的问题之前,并行编程看起来更像是一门艺术而非科学。 以下是简短的版本:用简单的方法编写代码。不要开始处理并行性,除非它成为一个问题。您仍然会遇到并行性。在本章中,我们将介绍一些为并行执行而编写的Java库方法。因此,您必须对它有足够的了解,以便进行基本的讨论,并避免出现错误。 在阅读并发编程这一章之后,您将更深入地理解它(但是,唉,这还远远不够。只是这些的话,充分理解这个主题是不可能的)。 在某些情况下,即使您只有一个处理器,无论您是否显式地尝试并行,并行实现是惟一的、最佳的或最符合逻辑的选择。它是一个可以一直使用的工具,所以您必须了解它的相关问题。 最好从数据的角度来考虑并行性。对于大量数据(以及可用的额外处理器),并行可能会有所帮助。但您也可能使事情变得更糟。 在本书的其余部分,我们将遇到不同的情况: - 1、所提供的惟一选项是并行的。这很简单,因为我们别无选择,只能使用它。这种情况是比较罕见的。 - 2、有多个选项,但是并行版本(通常是最新的版本)被设计成在任何地方都可以使用(甚至在那些不关心并行性的代码中),如案例#1。我们将按预期使用并行版本。 - 3、案例1和案例2并不经常发生。相反,您将遇到某些算法的两个版本,一个用于并行使用,另一个用于正常使用。我将描述并行的一个,但不会在普通代码中使用它,因为它也许会产生所有可能的问题。 我建议您在自己的代码中采用这种方法。 [http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html](要进一步了解为什么这是一个难题,请参阅Doug Lea的文章。) **parallelSetAll()** 流式编程产生优雅的代码。例如,假设我们想要创建一个数值由从零开始填充的长数组: ```JAVA // arrays/CountUpward.java import java.util.stream.LongStream; public class CountUpward { static long[] fillCounted(int size) { return LongStream.iterate(0, i -> i + 1).limit(size).toArray(); } public static void main(String[] args) { long[] l1 = fillCounted(20); // No problem show(l1); // On my machine, this runs out of heap space: // - long[] l2 = fillCounted(10_000_000); } } /* Output: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] */ ``` **流** 实际上可以存储到将近1000万,但是之后就会耗尽堆空间。常规的 **setAll()** 是有效的,但是如果我们能更快地处理如此大量的数字,那就更好了。 我们可以使用 **setAll()** 初始化更大的数组。如果速度成为一个问题,**Arrays.parallelSetAll()** 将(可能)更快地执行初始化(请记住并行性中描述的问题)。 ```JAVA // arrays/ParallelSetAll.java import onjava.*; import java.util.Arrays; public class ParallelSetAll { static final int SIZE = 10_000_000; static void intArray() { int[] ia = new int[SIZE]; Arrays.setAll(ia, new Rand.Pint()::get); Arrays.parallelSetAll(ia, new Rand.Pint()::get); } static void longArray() { long[] la = new long[SIZE]; Arrays.setAll(la, new Rand.Plong()::get); Arrays.parallelSetAll(la, new Rand.Plong()::get); } public static void main(String[] args) { intArray(); longArray(); } } ``` 数组分配和初始化是在单独的方法中执行的,因为如果两个数组都在 **main()** 中分配,它会耗尽内存(至少在我的机器上是这样。还有一些方法可以告诉Java在启动时分配更多的内存)。