Java - Hilos

 
Vista:
sin imagen de perfil

Hilos

Publicado por José Daniel (1 intervención) el 26/11/2022 21:18:20
La empresa UXZ requiere controlar la existencia de 90000000 productos (generar los valores de forma aleatoria), los cuales se almacenan en un vector A, mientras que los pedidos de los clientes de estos productos se almacenan en un vector B (generar los valores de forma aleatoria). Se requiere crear un tercer vector C que represente lo que se requiere comprar para mantener el stock(cantidad de inventario), para esto se considera lo siguiente: si los valores correspondientes de los vectores A y B son iguales se almacena este mismo valor, si el valor de B es mayor que el de A se almacena el doble de la diferencia entre B y A, si se da el caso de que A es mayor que B, se almacena B; estos cálculos indican lo que se requiere comprar para mantener el stock de inventario. La empresa UXZ, adicionalmente requiere conocer el valor más alto en los pedidos realizados.

Realice el programa en JAVA que permita almacenar a la información pertinente en los vectores A, B, C y muestre el valor más alto en pedidos.

Comparar el tiempo de ejecución al resolver el problema sin hilos y con hilos.
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder
Imágen de perfil de Kabuto
Val: 3.428
Oro
Ha mantenido su posición en Java (en relación al último mes)
Gráfica de Java

Hilos

Publicado por Kabuto (1381 intervenciones) el 27/11/2022 19:27:24
Aquí tendríamos 4 procesos:
- Llenar el vectorA (con valores Random)
- Llenar el vectorB (con valores Random)
- Llenar el vectorC (con valores que dependen de vectores A y B)
- Obtener el valor mayor en vectorC

De esos 4 procesos, creo que solo podemos aplicar hilos a los dos primeros.
Es decir, el llenado del vector A y B se puede hacer de forma simultánea en hilos separados.

Pero no el del vector C, ya que este requiere que los vectores A y B ya estén llenos, así que no puede ser un proceso simultáneo.

Lo mismo con el proceso de obtener el valor mayor, pues no puede hacerse hasta que no esté lleno C

Así que podemos escribir estos 4 procesos en distintos métodos separados y llamarlos dos veces.
La primera vez sin hilos y una segunda vez aplicando hilos a los métodos que sí pueden ejercer su tarea de forma simultánea.

En ambas ejecuciones, calcularemos el tiempo de inicio y final para medir lo que tarda cada uno.


Vale, pues he escrito un código para probar esto..... y tengo dudas de si lo he hecho bien.
Porque la ejecución SIN hilos resulta ser bastante más rápida que la versión CON hilos...., y se supone que debería ser al revés ...

Así que no estoy seguro de que esta solución sea correcta...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import java.time.LocalTime;
import java.util.Random;
 
public class Pedidos {
 
	private static int[]vectorA = new int[90000000];
	private static int[]vectorB = new int[90000000];
	private static int[]vectorC = new int[90000000];
	private static Random azar = new Random();
	private static LocalTime inicio, fin;
 
	public static void main(String[] args) {
 
		System.out.println("\t\t--Version SIN hilos--");
 
		inicio = LocalTime.now();
 
		llenarA();
		llenarB();
		llenarC();
		System.out.println("Valor del pedido mas alto: " + pedidoMasAlto());
 
		fin = LocalTime.now();
		long nanoSegundosSin = fin.toNanoOfDay() - inicio.toNanoOfDay();
		System.out.printf("Tiempo empleado: %d nanoSegundos\n", nanoSegundosSin);
 
 
 
		/*------------------------------------------------------------------*/
 
		System.out.println("\n\t\t--Version CON hilos--");
		//Preparamos hilos
		Runnable runA = new Runnable() {
			@Override
			public void run() {
				llenarA();
			}
		};
		Runnable runB = new Runnable() {
			@Override
			public void run() {
				llenarB();
			}
		};
		Thread hiloA = new Thread(runA);
		Thread hiloB = new Thread(runB);
		//Activamos hilos
		inicio = LocalTime.now();
		hiloA.start();
		hiloB.start();
		try {
			//Programa no puede continuar hasta que terminen los hilos
			hiloA.join();
			hiloB.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
 
		llenarC();
		System.out.println("Valor del pedido mas alto: " + pedidoMasAlto());
 
		fin = LocalTime.now();
		long nanoSegundosCon = fin.toNanoOfDay() - inicio.toNanoOfDay();
		System.out.printf("Tiempo empleado: %d nanoSegundos\n", nanoSegundosCon);
 
		/*------------------------------------------------------------------*/
 
		if (nanoSegundosCon < nanoSegundosSin)
			System.out.printf("\nLa version CON hilos ha sido %d nanosegundos mas rapido",
					nanoSegundosSin - nanoSegundosCon);
		else
			System.out.printf("\nLa version SIN hilos ha sido %d nanosegundos mas rapido",
					nanoSegundosCon - nanoSegundosSin);
 
	}
 
	private static void llenarA() {
		for (int i = 0; i < vectorA.length; i++)
			vectorA[i] = azar.nextInt(1000);
		System.out.println("Vector A llenado");
	}
 
	private static void llenarB() {
		for (int i = 0; i < vectorB.length; i++)
			vectorB[i] = azar.nextInt(1000);
		System.out.println("Vector B llenado");
	}
 
	private static void llenarC() {
		for (int i = 0; i < vectorA.length; i++) {
			if (vectorA[i] == vectorB[i])
				vectorC[i] = vectorA[i]; //Mismo valor
			else if (vectorA[i] < vectorB[i])
				vectorC[i] = (vectorB[i] - vectorA[i]) * 2; //Doble de la diferencia entre B y A,
			else
				vectorC[i] = vectorB[i]; //Se almacena B
		}
		System.out.println("Vector C llenado");
	}
 
	private static int pedidoMasAlto() {
		int mayor = vectorC[0];
		for (int i = 0; i < vectorC.length; i++) {
			if(vectorC[i] > mayor)
				mayor = vectorC[i];
		}
 
		return mayor;
	}
 
}


Si lo probamos, la ejecución SIN hilos siempre gana:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
--Version SIN hilos--
Vector A llenado
Vector B llenado
Vector C llenado
Valor del pedido mas alto: 1998
Tiempo empleado: 1123134300 nanoSegundos
 
		--Version CON hilos--
Vector B llenado
Vector A llenado
Vector C llenado
Valor del pedido mas alto: 1998
Tiempo empleado: 4486059100 nanoSegundos
 
La version SIN hilos ha sido 3362924800 nanosegundos mas rapido
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Hilos

Publicado por Tom (1831 intervenciones) el 28/11/2022 08:12:23
En principio yo no creo que se deban poner los procesos "A" y "B" en paralelo ... no me parece muy apropiado permitir pedidos de productos que aún no has creado. Lo que yo intentaría es usar hilos para cada uno de los tres procesos.

Por otra parte, lo que ves raro quizás viene de aquí (copio y pego de Random):

"Instances of java.util.Random are threadsafe. However, the concurrent use of the same java.util.Random instance across threads may encounter contention and consequent poor performance. Consider instead using ThreadLocalRandom in multithreaded designs"
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Hilos

Publicado por Tom (1831 intervenciones) el 28/11/2022 09:22:25
Me refiero a algo como esto, pero terminado y mejor organizado:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Orders {
	/* */
	static long runParallel() {
		int inventory[] = new int[90_000_000];
		int orders[] = new int[90_000_000];
		IntStream.range(0, 90_000_000).parallel().forEach(i -> inventory[i] = ThreadLocalRandom.current().nextInt(1001));
		IntStream.range(0, 90_000_000).parallel().forEach(i -> orders[i] = ThreadLocalRandom.current().nextInt(1001));
		return 0L;
	}
	/* */
	static long runSequential() {
		int inventory[] = new int[90_000_000];
		int orders[] = new int[90_000_000];
		IntStream.range(0, 90_000_000).forEach(i -> inventory[i] = ThreadLocalRandom.current().nextInt(1001));
		IntStream.range(0, 90_000_000).forEach(i -> orders[i] = ThreadLocalRandom.current().nextInt(1001));
		return 0L;
	}
	/* */
	public static void main(String args[]) {
		long start = System.nanoTime();
		runSequential();
		System.out.printf("Sequential run: %d\n", System.nanoTime() - start);
		System.gc();
		start = System.nanoTime();
		runParallel();
		System.out.printf("Parallel run  : %d\n", System.nanoTime() - start);
	}
}
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de Kabuto
Val: 3.428
Oro
Ha mantenido su posición en Java (en relación al último mes)
Gráfica de Java

Hilos

Publicado por Kabuto (1381 intervenciones) el 28/11/2022 10:10:01
Hola Tom.

Sí, el problema era el Random.
Horas después de publicar mi código, pensando en el asunto me di cuenta de que los hilos estaban compartiendo una misma instancia del objeto Random y supuse que eso podría ralentizar los hilos.
Y veo que esto lo confirma el fragmento de texto que has publicado

Acabo de hacer una prueba, dotando a cada hilo de su propio Random en lugar de compartirlo, y se han cambiado las tornas.

Elimino el Random que había declarado como atributo global:

1
2
3
4
5
6
7
public class Pedidos {
 
	private static int[]vectorA = new int[90000000];
	private static int[]vectorB = new int[90000000];
	private static int[]vectorC = new int[90000000];
	private static Random azar = new Random();
	private static LocalTime inicio, fin;

Y los métodos llenarA() y llenarB() usan cada uno su propio objeto Random

1
2
3
4
5
6
7
8
9
10
11
12
13
private static void llenarA() {
		Random azar = new Random();
		for (int i = 0; i < vectorA.length; i++)
			vectorA[i] = azar.nextInt(1000);
		System.out.println("Vector A llenado");
	}
 
	private static void llenarB() {
		Random azar = new Random();
		for (int i = 0; i < vectorB.length; i++)
			vectorB[i] = azar.nextInt(1000);
		System.out.println("Vector B llenado");
	}

Ahora sí, la versión con hilos es notablemente más rápida:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
--Version SIN hilos--
Vector A llenado
Vector B llenado
Vector C llenado
Valor del pedido mas alto: 1998
Tiempo empleado: 1041162900 nanoSegundos
 
		--Version CON hilos--
Vector B llenado
Vector A llenado
Vector C llenado
Valor del pedido mas alto: 1998
Tiempo empleado: 715650300 nanoSegundos
 
La version CON hilos ha sido 325512600 nanosegundos mas rapido


Luego probaré con ThreadLocalRandom, a ver si hay diferencias.
Muchas gracias por tu aporte Tom.
Saludos.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar