¿Cuál de estas dos implementaciones simultáneas es un mejor más rápido

prana:

Tengo dos implementaciones de generación de números primos en paralelo. El código del núcleo se ha tomado de otro post aquí en Stackoverflow.

Me gustaría saber cuál de estas implementaciones se prefiere y por qué? Además, si hay soluciones mejores y más rápidos para esto?

Implementación 1:

import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class PrimeThreads {

    private static int currentPrime = 0;

    public static void main(String[] args) {

        Object lock = new Object();

        Thread primerGenThread = new Thread(() -> {
            String threadName = Thread.currentThread().getName();
            System.out.println("Starting thread: " + threadName);
            int currentPrimeNo = 0;
            synchronized (lock) {
                try {
                    currentPrimeNo = generateNextPrime();
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
            }
            System.out.println("Prime Number Associated with this thread " + threadName + " is: " + currentPrimeNo);
            System.out.println("Completed thread: " + threadName);
        });

        System.out.println("****This is where the project starts*****");

        Scanner reader = new Scanner(System.in);
        System.out.print("Enter number of threads you want to create: ");
        int n = reader.nextInt();
        reader.close();

        ExecutorService executor = Executors.newFixedThreadPool(n);
        for(int i=1;i<=n; i++) {
            executor.submit(primerGenThread);
        }
        executor.shutdown();
        try {
            executor.awaitTermination(10, TimeUnit.MINUTES);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        System.out.println("****This is where the project ends*****");

    }

    private static int generateNextPrime() throws InterruptedException {

        long startTime = System.nanoTime();

        currentPrime++;
        if (currentPrime < 2) {
            currentPrime = 2;
            return currentPrime;
        }
        for (int i = 2; i < currentPrime; i++) {
            if (currentPrime % i == 0) {
                currentPrime++;
                i = 2;
            } else {
                continue;
            }
        }       

        long endTime = System.nanoTime();
        System.out.println("Time taken: " + (endTime - startTime) + " naoseconds.");
        return currentPrime;
    }

}

Y la aplicación 2:

import java.util.Scanner;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class PrimeAsyncThreads {

    private static int currentPrime = 0;

    public static void main(String[] args) {

        System.out.println("****This is where the project starts*****");

        Scanner reader = new Scanner(System.in);
        System.out.print("Enter number of threads you want to create: ");
        int n = reader.nextInt();
        reader.close();

        ExecutorService executor = Executors.newFixedThreadPool(n);

        for (int i = 1; i <= n; i++) {
            CompletableFuture.supplyAsync(() -> {
                try {
                    return generateNextPrime();
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
                return n;
            }, executor).thenAccept(s -> System.out.println("Prime Number Associated with this thread "
                    + Thread.currentThread().getName() + " is: " + currentPrime));
        }

        executor.shutdown();

        try {
            executor.awaitTermination(10, TimeUnit.MINUTES);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }

        System.out.println("****This is where the project ends*****");
    }

    private static int generateNextPrime() throws InterruptedException {

        long startTime = System.nanoTime();

        currentPrime++;
        if (currentPrime < 2) {
            currentPrime = 2;
            return currentPrime;
        }
        for (int i = 2; i < currentPrime; i++) {
            if (currentPrime % i == 0) {
                currentPrime++;
                i = 2;
            } else {
                continue;
            }
        }

        long endTime = System.nanoTime();
        System.out.println("Time taken: " + (endTime - startTime) + " naoseconds.");
        return currentPrime;
    }
}

Agradecemos sus sugerencias y ayuda.

EDIT: También se dio cuenta de que la segunda aplicación no garantiza que cada hilo tendrá un nuevo primo. En este caso, a veces múltiples hilos reciben el mismo valor de la variable currentPrime.

Gracias.

Steve Benett:

La principal diferencia entre estas implementaciones es la forma en que se ejecutan.

Implempentation 1 es básicamente igual a una ejecución secuencial. No hay ninguna ventaja de utilizar hilos porque cómo se utiliza el bloque sincronizado. Cada hilo espera para el hilo anterior se completen antes de que se genere el próximo primer.

Usted ya habrá notado que la aplicación 2 calcula los mismos primos varias veces. Esto es porque no hay sincronización. Sólo el contador currentPrimese utiliza para tener alguna forma de control de qué número debe ser considerado como primer en el siguiente hilo.

Por lo tanto, ambas implementaciones no son capaces de calcular números primos en paralelo para producir un resultado viable.

Piense en la rutina. Se utiliza un valor para determinar si es un número primo. Este valor debe ser la entrada para cada hilo para hacer el cálculo. Ahora, la única cosa a considerar es cómo hacer que este seguro para hilos valor para asegurarse de que sólo se utiliza una vez.

Esto se puede achived, por ejemplo, utilizando una variable Atómica para currentPrime.

Otra mejora podría ser para incrementar currentPrimefuera del generateNextPrime()método. Este método podría tomar el valor como un parámetro. Algo como

generateNextPrime(currentPrime.incrementAndGet());

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=282129&siteId=1
Recomendado
Clasificación