Suppose you want to do something like this: give you an array of type double, let you ask for the reciprocal of the elements of this array, and what do you do? Of course, the countdown first, and then the sum. Yes, that's it, but what if you have multiple CPU cores? For example, four cores, is it a linear way to ask if you're wasting computing resources, or not taking full advantage of multicore conditions to reduce execution time? Is it possible to split this array into 4 segments, each of which computes the reciprocal of a section, and then computes the completion, and then adds the result? Of course! Should do so, what to do in Java? Using the Fork/join framework, one of the methods used is to use the Recursiveaction class, as long as we create a new task class to inherit the class, the key is to rewrite its compute () method to implement its computational logic. Here is an example of a generalization to accomplish this task:
Package edu.coursera.parallel; Import java.util.concurrent.RecursiveAction; /** * Class Wrapping methods for implementing reciprocal array sum in parallel. */public Final class Reciprocalarraysum {/** * Default constructor. */Private Reciprocalarraysum () {} private static int getncores () {String ncoresstr = system.getenv ("CO Ursera_grader_ncores "); if (ncoresstr = = null) {return runtime.getruntime (). Availableprocessors (); } else {return integer.parseint (NCORESSTR); }}/** * sequentially compute the sum of the reciprocal values for a given array. * * @param input Input array * @return The sum of the reciprocals of the array input */protected static do Uble seqarraysum (final double[] input) {double sum = 0; Compute sum of reciprocals of array elements for (int i = 0; i < input.length; i++) {sum + = 1/i Nput[i]; } return sum; }/** * Computes the size of each chunk, given the number of chunks to create * across a given number of ele ments. * * @param nchunks The number of chunks to create * @param nelements the number of elements to chunk across * @return The default chunk size */private static int getchunksize (final int nchunks, final int nelements) { Integer Ceil return (nelements + nChunks-1)/nchunks; }/** * Computes the inclusive element index that the provided chunk starts at, * given there is a certain nu Mber of chunks. * * @param chunk the chunk to compute the start of * @param nchunks the number of chunks created * @param nele ments the number of elements to chunk across * @return The inclusive index that this chunk starts at the set of * Nelements */private static int getchunkstartinclusive (final int chunk, final int nchunks, FI nal int nelements) {final int chunksiZe = getchunksize (nchunks, nelements); return chunk * chunkSize; }/** * Computes the exclusive element index that the provided chunk ends at, * Given there is a certain numb Er of chunks. * * @param chunk the chunk to compute the end of * @param nchunks the number of chunks created * @param neleme NTS the number of elements to chunk across * @return The exclusive end index for this chunk */private static I NT getchunkendexclusive (final int chunk, final int nchunks, final int nelements) {final int chunkSize = Getchunksize (Nchunks, nelements); Final int end = (chunk + 1) * chunkSize; if (End > Nelements) {return nelements; } else {return end; }}/** * This class stub can is filled in to implement the body of each task * created to perform Reciproc Al array sum in parallel. */private static class Reciprocalarraysumtask extends Recursiveaction { /** * Starting index for traversal do by this task. */private final int startindexinclusive; /** * Ending index for traversal do by this task. */private final int endindexexclusive; /** * Input array to reciprocal sum. */private final double[] input; /** * Intermediate value produced by the this task. */private Double value; /** * Constructor. * @param setstartindexinclusive Set The starting index to begin * Parallel traversal at. * @param setendindexexclusive Set ending index for parallel traversal. * @param setinput Input values */reciprocalarraysumtask (final int setstartindexinclusive, F inal int setendindexexclusive, final double[] setinput) {this.startindexinclusive = setstartindexinclusive; This.endindexexclusive = setendindexexclusive; This. input = SetInput; }/** * Getter for the value produced by this task. * @return value produced by the This task */public double GetValue () {return Value; } @Override protected void Compute () {//TODO//Calculate sequentially V alue = 0; for (int i = startindexinclusive; i < endindexexclusive; i++) {value + = 1/input[i]; }}}/** * todo:modify This method to compute the same reciprocal sum as * seqarraysum, and use TW o tasks running in parallel under the Java Fork * Join framework. Assume that's the length of the input array is * evenly divisible by 2. * * @param input Input array * @return The sum of the reciprocals of the array input */protected static do Uble pararraysum (final double[] input) {assert Input.length% 2 = = 0; int mid = INPUT.LENGTH/2; ReciProcalarraysumtask lower = new Reciprocalarraysumtask (0, Mid, input); Reciprocalarraysumtask high = new Reciprocalarraysumtask (Mid, input.length, input); Lower.fork (); High.compute (); Lower.join (); Return Lower.getvalue () +high.getvalue (); }/** * Todo:extend The work do you do to implement pararraysum to use a set * number of tasks to compute the R Eciprocal array sum. You could find the * above utilities getchunkstartinclusive and getchunkendexclusive helpful * in computing the rang E of element indices that belong to each chunk. * * @param input input array * @param numtasks the number of tasks to create * @return The sum of the Reciproc ALS of the array input */protected static double Parmanytaskarraysum (final double[] input, final int nu mtasks) {int tasknum = Numtasks; if (tasknum>input.length) {tasknum = Input.length; } reciprocalarraysumtask[] Tasks = nEW Reciprocalarraysumtask[tasknum]; int i = 0; for (i=0; i<tasknum-1; i++) {tasks[i] = new Reciprocalarraysumtask (getchunkstartinclusive (i, Tasknum, INPUT.L Ength), getchunkendexclusive (i, Tasknum, input.length), input); Tasks[i].fork (); } Tasks[i] = new Reciprocalarraysumtask (getchunkstartinclusive (i, Tasknum, input.length), getchunkendexclusive (I, t Asknum, input.length), input); Tasks[i].compute (); for (int j=0; j<tasknum-1; J + +) {tasks[j].join (); } double sum = 0; for (int j=0; j<tasknum; J + +) {sum + = Tasks[j].getvalue (); } return sum; } public static void Main (string[] args) {double[] arr = {2,4,8,10}; Double seq = seqarraysum (arr); Double half = pararraysum (arr); Double many = Parmanytaskarraysum (arr, 4); System.out.println (seq); SYSTEM.OUT.PRINTLN (half); System.out.println (many); }}
Application of Java Fork/join Framework Small test and Recursiveaction class