Tengo un problema de rendimiento que he intentado resolver mediante paralelización. Aunque he obtenido mejor rendimiento, sigue siendo un rendimiento pobre. A ver si a alguien se le ocurre algo:
Tengo una aplicación en JavaFX que muestra una tabla. Esa tabla tiene una columna donde se muestra una imagen:
El problema viene con el objeto que pinta la imagen. La instanciación de ese objeto es muy costosa, y se debe instanciar tantas veces como filas tenga la tabla. Cada tabla tiene de media unas 350 filas, con lo que usando una solución secuencial, la pantalla tarda en renderizarse hasta 14 segundos.
List<SetCardTableRecord> tableRecords = cardService.findAllBySet(set).stream().map(SetCardTableRecord::new).collect(Collectors.toList());
El primer cambio ha sido sustituir el stream por parallelStream, mejorando de 14 a 6 segundos:
List<SetCardTableRecord> tableRecords = cardService.findAllBySet(set).parallelStream().map(SetCardTableRecord::new).collect(Collectors.toList());
Pero sigue sin ser suficiente. Entonces he optado por paralelizar yo el proceso; parto la lista de registros en N sublistas de 10 elementos y lanzo N hilos de ejecución:
List<SetCardTableRecord> tableRecords = new ArrayList<>();
List<Card> cards = cardService.findAllBySet(set);
int chunkSize = 10;
int finalized = 0;
AtomicInteger counter = new AtomicInteger();
Collection<List<Card>> cardsChunkedList = cards.stream().collect(Collectors.groupingBy(it -> counter.getAndIncrement() / chunkSize)).values();
ExecutorService executorService = Executors.newFixedThreadPool(cardsChunkedList.size());
CompletionService<List<SetCardTableRecord>> completionService = new ExecutorCompletionService<>(executorService);
for (List<Card> cardsChunked : cardsChunkedList) {
completionService.submit(new SetTableRecordCallable(cardsChunked));
}
while (finalized < cardsChunkedList.size()) {
try {
Future<List<SetCardTableRecord>> future = completionService.take();
tableRecords.addAll(future.get());
finalized++;
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
Esto presenta una ligera mejora, ya que el tiempo baja a 4 segundos, pero sigue siendo demasiado. He ido jugando con el nº de elementos de las sublistas, pero los valores entre 10 y 15 son los óptimos. Si bajo de 10, el overhead de crear los hilos penaliza, y si subo a 20 o más, la instanciación del objeto de la imagen penaliza el tiempo.
¿A alguien se le ocurre una mejor manera de paralelizar o de resolver este problema? Lo ideal es que el tiempo de ejecución de esta rutina sea de 0,5 a 1,5 segundos.