答复: Demo for Parallel Core Collection API
Tristan Yan
tristan.yan at oracle.com
Tue Feb 4 01:58:10 UTC 2014
Hi Paul
I know this may be a little bit late. But I am still asking you review this.
http://cr.openjdk.java.net/~tyan/JDK-8033358/webrev.01/
This is a whole demo code include the stream demo code you reviewed before also included parallel part. There is one other parallel demo that Paul has already pushed.
Could you please review it again?
Thank you so much
Tristan
-----邮件原件-----
发件人: Paul Sandoz
发送时间: Tuesday, January 14, 2014 9:27 PM
收件人: core-libs-dev at openjdk.java.net
抄送: Tristan Yan
主题: Re: Demo for Parallel Core Collection API
Hi Tristan,
See below for a patch.
The location of the code seems a little out of place with the other code. I would have expected a structure such as:
stream/parallel/*.java
where the source code is in the default no-package.
I am not yet convinced of the value of the RandomPrimeNumber example. In your original code you had a parallel stream invoking another parallel stream in the filter (the simple division to return a prime), this has the effect of actually slowing down the computation due to each calculation fighting for F/J resources and threads. Remove the additional parallelism and it is not clear when eyeballing the execution time that parallel is faster than sequential (it probably is, but it is handy to have obvious examples). A simpler example is to generate a list of probable primes of a certain bit length.
IMHO a better example in the category of "slightly more complex" is the rendering of the Mandelbrot set, parallelized along the real or imaginary axis. Once can easily generate some nice ASCII-like art :-)
Paul.
On Dec 20, 2013, at 6:25 PM, Paul Sandoz <Paul.Sandoz at oracle.com> wrote:
> Thanks, I need to look at this in more detail, but here are some quick comments.
>
> - recommend you try and avoid using limit with parallel ops, for example the Pi example cam be reformulated as:
>
> long M = LongStream.range(0, N).parallel().filter(sr -> {
> double x = ThreadLocalRandom.current().nextDouble(-1, 1);
> double y = ThreadLocalRandom.current().nextDouble(-1, 1);
>
> return x * x + y * y < R * R; // Don't use need to use sqrt
> }).count();
> double pi = (M / N) * 4.0;
>
> the Primes example could be reformulated as:
>
> LongStream.range(0, limit).parallel().map(/odd
> values/).filter(RandomPrimeNumber::isPrime).findAny();
>
> you don't need to declare unordered() since findAny implicitly makes the stream unordered by definition.
>
> The key message here is range has better decomposition characteristics than generate or iterate.
>
> More later, probably after the break,
> Paul.
diff -r d56cd0872ec4 src/share/sample/demo/parallel/MonteCarloPI.java
--- a/src/share/sample/demo/parallel/MonteCarloPI.java Tue Jan 14 13:34:22 2014 +0100
+++ b/src/share/sample/demo/parallel/MonteCarloPI.java Tue Jan 14 14:15:22 2014 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions @@ -36,16 +36,14 @@
* input validation and proper error handling, might not be present in
* this sample code.
*/
-package demo.parallel;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.LongStream;
/**
- * This demo shows how to use the parallel mode and the Monte Carlo method to
- * calculate the value of PI
+ * This demo shows how to use parallel streams to approximately
+ calculate the
+ * value of π using the Monte Carlo method.
*
- * @author tyan
*/
public class MonteCarloPI {
@@ -62,39 +60,32 @@
}
/**
- * Use the Monte Carlo method to calculate the value of PI. basic algorithm
+ * Use the Monte Carlo method to calculate the value of π. basic
+ algorithm
* is: 1. Draw a square on the ground, then inscribe a circle within it. 2.
* Scatter some objects of uniform size (grains of rice or sand) over the
* square. 3. Count the total number of objects inside the circle and the
- * total number of objects overall. 4. The ratio of the two total is an
- * estimate of the ratio of the two areas, which is PI/4. Multiply the
- * result by 4 to estimate PI.
+ * total number of objects overall. 4. The ratio of the two totals is an
+ * estimate of the ratio of the two areas, which is pi/4. Multiply the
+ * result by 4 to estimate π.
*
- * @param x how many times randomly selected a point
- * @return value of π by x times calculation
+ * @param n how many times to randomly selected a point
+ * @return the approximate value of π
*/
- private static double pi(long x) {
- return LongStream.generate(() -> hit()).
- // using parallel mode
- parallel().
- // select only x elements
- limit(x).sum()
- // perform division before multiplication to reduce ovefflow
- // risk
- / (double) x * 4;
+ private static double pi(long n) {
+ long m = LongStream.range(0, n).parallel().filter(i -> hit()).count();
+ return (m / (double) n) * 4.0;
}
/**
- * Use ThreadLocalRandom to simulate that whether a point is inside the
- * circle or outside the circle
+ * Use ThreadLocalRandom to simulate that whether a point is inside a
+ * circle, of radius 1, or outside.
*
- * @return 1 randomly selected point is inside the circle 0 randomly
- * selected point is outside the circle
+ * @return true if within the circle, otherwise false
*/
- private static long hit() {
+ private static boolean hit() {
ThreadLocalRandom lr = ThreadLocalRandom.current();
- double x = lr.nextDouble(1.0);
- double y = lr.nextDouble(1.0);
- return Math.sqrt(y * y + x * x) <= 1.0 ? 1 : 0;
+ double x = lr.nextDouble(-1.0, 1.0);
+ double y = lr.nextDouble(-1.0, 1.0);
+ return x * x + y * y <= 1.0;
}
}
diff -r d56cd0872ec4 src/share/sample/demo/parallel/RandomPrimeNumber.java
--- a/src/share/sample/demo/parallel/RandomPrimeNumber.java Tue Jan 14 13:34:22 2014 +0100
+++ b/src/share/sample/demo/parallel/RandomPrimeNumber.java Tue Jan 14 14:15:22 2014 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions @@ -36,19 +36,19 @@
* input validation and proper error handling, might not be present in
* this sample code.
*/
-package demo.parallel;
import java.math.BigInteger;
import static java.math.BigInteger.ONE; import java.util.BitSet; import java.util.OptionalLong; import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.LongStream;
/**
- * This demo shows how to use the parallel mode to find an unknown lengths
- * prime number. The process includes dividing the computation area to an m * n
- * segment and then randomly selecting mth and nth segments to try to find a
+ * This demo shows how to use parallel streams to find a prime number.
+ * The process includes dividing the computation area to an m * n
+ * segments and then randomly selecting mth and nth segments to try to
+ find a
* prime number in the computation area. If there is no prime number in this
* segment, then this process is repeated until the entire segment has been
* examined. Either there will be no prime number in this area, or the first @@ -91,7 +91,7 @@
+ "prime number");
return;
}
- Random random = new Random(System.currentTimeMillis());
+ Random random = ThreadLocalRandom.current();
/*
* Prime number can not be a even number; it must be odd number.
*/
@@ -140,23 +140,15 @@
long start = first_number.longValue()
+ randomHighSeg * LOW_BIT_SEGMENT * SEGMENT_SIZE
+ randomLowSeg * SEGMENT_SIZE;
- OptionalLong anyPrime = LongStream.iterate(start, l -> l + 2).
- // You must first specify the limit to guarantee that
- // the length of the number is an acceptable length.
- limit(limit).
- // From this point, use parallel().
- // You have to find only one prime number, so the
- // order is not important. Also, an unordered stream
- // is more efficient than an ordered stream.
+
+ OptionalLong anyPrime = LongStream.range(0, limit).
parallel().
- // we only need find one prime number, so keeping
- // order is not needed. Also unordered stream is
- // more efficient than ordered stream.
- unordered().
+ // Generate a sequence of limit elements as as follows
+ // start, start + 2, start + 4, start + 6
+ map(n -> n * 2 + start).
// Filter only the prime number
filter(RandomPrimeNumber::isPrime).
- //Stop the process as soon as you find a prime
- //number.
+ // Stop the process as soon as you find a prime number.
findAny();
if (anyPrime.isPresent()) {
System.out.println(String.format( @@ -176,13 +168,12 @@
/**
* Decide if a BigInteger is a prime number
*
- * @param integer a number
+ * @param number a number
* @return true if integer is a prime number false if integer is not a prime
* number
*/
private static boolean isPrime(long number) {
- //This is a parall version that checks if a number is a prime number
- return !LongStream.range(2L, Math.round(Math.sqrt(number))).parallel().
+ return !LongStream.range(2L, Math.round(Math.sqrt(number))).
anyMatch(divisor -> number % divisor == 0);
}
More information about the core-libs-dev
mailing list