1

i want this code in Java 1.8 to run parallel on more processors:

        // Make iterations
        for(int i = 0; i < numberOfIterations; i++) {
            for(int m = 0; m < gridsize; m++) {
                for(int n = 0; n < gridsize; n++) {
                    one_cell_generation(grid, grid2, m, n);
                }
                int n = 0;
            }

        }

It's part of the code from the game of life implementation. How can i make it parallel so the function one_cell_generation will run multiple times on more processors (perhaps threads?). I am new in Java. Thanks. Here is my whole code of the Game of Life implementation:

package gameoflife;

public class GameOfLife {

    public static int gridsize = 5;
    public static int numberOfIterations = 100;
    public static String liveCell = "x";
    public static String deadCell = "o";

    public static void main(String[] args) {
        // Probability that cell is live in random order
        double p = 0.1;

        Boolean[][] grid = new Boolean[gridsize][gridsize];
        Boolean[][] grid2 = new Boolean[gridsize][gridsize];


        // Set up grid
        for(int m = 0; m < gridsize; m++) {
            for(int n = 0; n < gridsize; n++) {
                grid[m][n] = false;
                if(Math.random() < p) {
                    grid[m][n] = true;
                }
                // Copy grid
                grid2[m][n] = grid[m][n];
            }
        }

        // Make iterations
        for(int i = 0; i < numberOfIterations; i++) {
            for(int m = 0; m < gridsize; m++) {
                for(int n = 0; n < gridsize; n++) {
                    one_cell_generation(grid, grid2, m, n);
                }
                int n = 0;
            }

        }

        print_grid(grid);


    }

    public static void print_grid(Boolean[][] grid) {
        for(int m = 0; m < gridsize; m++) {
            for(int n = 0; n < gridsize; n++) {
                if(grid[m][n] == false) {
                    System.out.print(deadCell);
                } else {
                    System.out.print(liveCell);
                }

            }
            System.out.println();
        }
    }

    public static void one_cell_generation(Boolean[][] oldGrid, Boolean[][] newGrid, int m, int n) {
        // count live and dead neighbors
        int liveNeighbours = 0;
        // iterate over neighbors
        // check borders
        if(m > 0) {
            if(oldGrid[m-1][n] == true) {
                liveNeighbours += 1;
            }
            if (n > 0) {
                if(oldGrid[m-1][n-1] == true) {
                    liveNeighbours += 1;
                }
            }
            if(n < (gridsize - 1)) {
                if (oldGrid[m-1][n+1] == true) {
                    liveNeighbours += 1;
                }
            }
        }
        if (m < (gridsize - 1)) {
            if (oldGrid[m+1][n] == true) {
                liveNeighbours += 1;
            }

            if(n > 0) {
                if(oldGrid[m+1][n-1] == true) {
                    liveNeighbours += 1;
                }
            }
            if(n < (gridsize - 1)) {
                if(oldGrid[m+1][n+1] == true) {
                    liveNeighbours += 1;
                }
            }
        }

        if (n > 0) {
            if (oldGrid[m][n-1] == true) {
                liveNeighbours += 1;
            }
        }
        if(n < (gridsize - 1)) {
            if(oldGrid[m][n+1] == true) {
                liveNeighbours += 1;    
            }
        }

        // conway's game of life rules
        // apply rules to new grid
        if(liveNeighbours < 2 || liveNeighbours > 3) {
            newGrid[m][n] = false;
        }
        if(liveNeighbours == 3) {
            newGrid[m][n] = true;
        }
    }

}

stepanVich
  • 318
  • 4
  • 11
  • 1
    What have you tried so far? – papaya Dec 25 '19 at 09:23
  • do you have some particular number of threads to run this method? explain "multiple times" please – Vault23 Dec 25 '19 at 09:25
  • i read this article https://stackoverflow.com/questions/27558605/java-8-parallel-for-loop but i did't realy catch up. – stepanVich Dec 25 '19 at 09:26
  • 1
    I donot know the exact code for game of life, but looking at what you have pasted here, there's lot of chances of ```concurrent modification execptions``` What will you do in that cases? – papaya Dec 25 '19 at 09:28
  • Ok, so if i have 4 processors i could create 4 threads. Or how would you parallize it? – stepanVich Dec 25 '19 at 09:29
  • 1
    This is not as easy as adding some threads. There have been [whole books](https://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601) written on the topic. Answering the question is off-topic for StackOverflow since it essentially means to restructure the whole program. And evenif the program wourd work as intended when run in parallel, there is no guarantee it would, in fact, decrease exeuction time. My best hint is: start reading. – Turing85 Dec 25 '19 at 09:35
  • @stepanVich like mentioned above, if you want to add some parallel tasks, you need to modify your variables with `Atomics` to prevent lots of problems according to race conditions etc. To achieve what you need, you can simply create `ExecutorService` with some number of threads in pool and execute your task with it. – Vault23 Dec 25 '19 at 09:35
  • The link you are sharing on parrellelization is possible using streams, but you need to change your code to include collections instead of primitive arrays for that – Shivam Puri Dec 25 '19 at 09:36
  • You're not copying the grid after each iteration. – Robby Cornelissen Dec 25 '19 at 09:36
  • As a joke which will start throwing exceptions, you can simply start of by adding a small part of the code like this: ```callables.add( () -> { one_cell_generation(grid, grid2, m, n); return true; });``` and do this ```for (Future booleanFuture : service.invokeAll(callables)) { try{ booleanFuture.get(); }catch (Exception e){ e.printStackTrace(); } }``` – papaya Dec 25 '19 at 09:37
  • @SiddarthSreeni There's no risk of concurrent modification exceptions as long as the time series in the outer loop is respected. The code uses arrays (not collections), and even if it did use collections, all operations just update one distinct location in the grid. – Robby Cornelissen Dec 25 '19 at 09:51
  • 1
    @ShivamPuri No need for collections. Can easily use an `IntStream` to iterate over a two-dimensional array. – Robby Cornelissen Dec 25 '19 at 09:53
  • @Vault23 There's no risk of race conditions and no need for atomics provided that the time series in the outer loop is respected. – Robby Cornelissen Dec 25 '19 at 09:54
  • @RobbyCornelissen what if 1 thread changed `int liveNeighbours0` and another thread did not? i can imagine tons of cases where `liveNeighbours` could be a bottle neck in this method if we will try to run it parallel – Vault23 Dec 25 '19 at 09:58
  • 2
    @Vault23 The `liveNeighbours` variable is local to the method. Every thread will have its own copy to work on. No risk, no bottleneck. – Robby Cornelissen Dec 25 '19 at 10:00
  • 1
    @RobbyCornelissen correct, thanks! i missed that – Vault23 Dec 25 '19 at 10:02
  • Edit: Earlier I posted "as a joke". Apparently it doesn't throw exceptions! – papaya Dec 25 '19 at 10:18

2 Answers2

1

The outer loop is a time series looping over the different generations, so that can not be parallelized without affecting the final results.

The two inner loops calculate the state of the current generation based on the state of the previous generation, and can easily be parallelized.

Here's an approach using a parallel IntStream:

static int numberOfIterations = 100;
static int gridSize = 5;

public static void main(String[] args) {
    Boolean[][] grid1 = new Boolean[gridSize][gridSize];
    Boolean[][] grid2 = new Boolean[gridSize][gridSize];

    // initialize grids here

    for(int i = 0; i < numberOfIterations; i++) {
        // parallel processing
        IntStream.range(0, gridSize * gridSize).parallel().forEach(mn -> {
            int m = mn / gridSize;
            int n = mn % gridSize;

            oneCellGeneration(grid1, grid2, m, n);
        });

        // copy new grid to old grid here
    }
}

public static void oneCellGeneration(Boolean[][] grid1, Boolean[][] grid2,
        int m, int n) {
    // your cell generation logic here
}

Note 1: I renamed some methods and variables to be in line with Java naming conventions.
Note 2: You forgot to copy the new grid to the old grid after finishing (or before starting) a generation in your original code.

Robby Cornelissen
  • 91,784
  • 22
  • 134
  • 156
0

You can do like this. I can't add coment to answer so I create my own answer.

    static int gridSize = 5;

    public static void main(String[] args) {
        Boolean[][] grid1 = new Boolean[gridSize][gridSize];
        Boolean[][] grid2 = new Boolean[gridSize][gridSize];

        // initialize grids here

            IntStream
                    .range(0, gridSize * gridSize)
                    .limit(numberOfIterations)
                    .parallel().forEach(mn -> {
                int m = mn / gridSize;
                int n = mn % gridSize;

                oneCellGeneration(grid1, grid2, m, n);
            });
    }

    public static void oneCellGeneration(Boolean[][] grid1, Boolean[][] grid2,
                                         int m, int n) {
        // your cell generation logic here
    }
    ```
AnnKont
  • 424
  • 4
  • 17