Estoy tratando de leer un archivo y agregar cada línea a una lista.
Dibujo sencillo explicando el objetivo.
Clase principal -
public class SimpleTreadPoolMain { public static void main(String[] args) { ReadFile reader = new ReadFile(); File file = new File("C:\\myFile.csv"); try { reader.readFile(file); } catch (IOException e) { e.printStackTrace(); } } }clase de lector -
public class ReadFile { ExecutorService executor = Executors.newFixedThreadPool(5);//creating a pool of 5 threads List<String> list = new ArrayList<>(); void readFile(File file) throws IOException { try (BufferedReader br = new BufferedReader(new FileReader(file))) { String line; while ((line = br.readLine()) != "") { Runnable saver = new SaveToList(line,list); executor.execute(saver);//calling execute method of ExecutorService } } executor.shutdown(); while (!executor.isTerminated()) { } } }Clase de ahorro -
public class SaveToList<E> implements Runnable{ List<E> myList; E line; public SaveToList(E line, List<E> list) { this.line = line; this.myList = list; } public void run() { //modify the line myList.add(line); } }Traté de tener muchos subprocesos de ahorro para agregar a la misma lista en lugar de agregar un protector a la lista uno por uno. Quiero usar subprocesos porque necesito modificar los datos antes de agregarlos a la lista. Así que asumo que modificar los datos tomaría algún tiempo. Entonces, poner en paralelo esta parte reduciría el consumo de tiempo, ¿verdad?
Pero esto no funciona. No puedo devolver una lista global que incluya todos los valores del archivo. Quiero tener solo una lista global de valores del archivo. Así que el código definitivamente debería cambiar. Si alguien me puede orientar se lo agradecería mucho.
Aunque agregar uno por uno en un solo subproceso funcionaría, usar un grupo de subprocesos lo haría más rápido, ¿verdad?
El uso de múltiples subprocesos no acelerará nada aquí.
Usted está:
Dado que está utilizando un ArrayList , necesita sincronizar el acceso a él, porque lo está mutando desde varios subprocesos. Entonces, está agregando cosas a la lista en serie.
Pero incluso sin la sincronización, el tiempo necesario para el IO superará con creces el tiempo necesario para agregar la cadena a la lista. Y agregar subprocesos múltiples solo lo ralentizará más, porque está trabajando para construir el ejecutable, enviarlo al grupo de subprocesos, programarlo, etc.
Es más simple perderse todo el paso intermedio:
Asi que:
try (BufferedReader br = new BufferedReader(new FileReader(file))) { String line; while (!(line = br.readLine()).isEmpty()) { list.add(line); } }De hecho, debería probar si vale la pena usar subprocesos múltiples en su aplicación, simplemente compare cuánto tiempo lleva leer todo el archivo sin ningún procesamiento en las filas y compárelo con el tiempo que lleva procesar en serie todo el archivo.
Si su proceso no es demasiado complejo, supongo que no vale la pena usar subprocesos múltiples.
Si encuentra que el tiempo que lleva es mucho más, entonces puede pensar en usar uno o más subprocesos para hacer los cálculos.
Si es así, podría usar Future s para procesar lotes de cadenas de entrada o tal vez podría usar una Cola segura para subprocesos para enviar cadenas a otro proceso.
private static final int BATCH_SIZE = 1000; public static void main(String[] args) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("big_file.csv"), "utf-8")); ExecutorService pool = Executors.newFixedThreadPool(8); String line; List<String> batch = new ArrayList<>(BATCH_SIZE); List<Future> results = new LinkedList<>(); while((line=reader.readLine())!=null){ batch.add(line); if(batch.size()>=BATCH_SIZE){ Future<Object> f = noWaitExec(batch, pool); results.add(f); batch = new ArrayList<>(BATCH_SIZE); } } Future<List> f = noWaitExec(batch,pool); results.add(f); for (Future future : results) { try { Object object = future.get(); // Use your results here } catch (Exception e) { // Manage this.... } } } private static Future<List> noWaitExec(final List<String> batch, ExecutorService pool) { return pool.submit(new Callable<List>() { public List call() throws Exception { List result = new ArrayList<>(batch.size()); for (String string : batch) { result.add(process(string)); } return result; } }); } private static Object process(String string) { // Your process .... return null; };Hay muchas otras soluciones posibles (Observables, ParallelStreams, Pipes, CompletableFutures ... lo que sea), aún así creo que la mayor parte del tiempo invertido es el tiempo que lleva leer el archivo, solo usando un BufferedInputStream para leer el archivo con un búfer lo suficientemente grande podría reducir sus tiempos más que la computación paralela.