resueltos programas para opciones multitarea multiproceso multihilos multihilo implementar hilos fuente ejemplos ejemplo codigo asincronos java multithreading pdf crystal-reports export

java - programas - ¿Cómo generar documentos PDF desde rpt en un enfoque multihilo?



multitarea en java (2)

Este es un código muy básico. Un ThreadPoolExecutor con un subproceso de tamaño fijo en un grupo es la columna vertebral.

Algunas consideraciones:

  1. El tamaño del grupo de subprocesos debe ser igual o menor que el tamaño del grupo de conexiones de base de datos. Y debe ser de un número óptimo, lo cual es razonable para los motores paralelos.
  2. El hilo principal debe esperar el tiempo suficiente antes de matar todos los hilos. He puesto 1 hora como tiempo de espera, pero eso es solo un ejemplo.
  3. Deberá tener el manejo adecuado de Excepción.
  4. Desde el documento API, vi los métodos stopAll y shutdown de la clase Engine. Entonces, lo invoco tan pronto como termina nuestro trabajo. Eso es nuevo, solo un ejemplo.

Espero que esto ayude.

import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.sql.Connection; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class RunEngine { public static void main(String[] args) throws Exception { final String rpt = "/tmp/rpt/input/rpt-1.rpt"; final String sFilePath = "/tmp/rpt/output/"; final String sFileName = "pdfreport"; final Object[] data = new Object[10]; ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(10); for (int i = 0; i < data.length; i++) { PDFExporterRunnable runnable = new PDFExporterRunnable(rpt, data[i], sFilePath, sFileName, i); executor.execute(runnable); } executor.shutdown(); executor.awaitTermination(1L, TimeUnit.HOURS); Engine.stopAll(); Engine.shutdown(); } private static class PDFExporterRunnable implements Runnable { private final String rpt; private final Object data; private final String sFilePath; private final String sFileName; private final int runIndex; public PDFExporterRunnable(String rpt, Object data, String sFilePath, String sFileName, int runIndex) { this.rpt = rpt; this.data = data; this.sFilePath = sFilePath; this.sFileName = sFileName; this.runIndex = runIndex; } @Override public void run() { // Loops Engine eng = new Engine(Engine.EXPORT_PDF); eng.setReportFile(rpt); // rpt is the report name Connection cn = null; /* * DB connection related code. Check and use. */ //if (cn.isClosed() || cn == null) { //cn = ds.getConnection(); //} eng.setConnection(cn); System.out.println(" After set connection"); eng.setPrompt(data, 0); ReportProperties repprop = eng.getReportProperties(); repprop.setPaperOrient(ReportProperties.DEFAULT_PAPER_ORIENTATION, ReportProperties.PAPER_FANFOLD_US); eng.execute(); System.out.println(" After excecute"); FileOutputStream fos = null; try { String FileName = sFileName + "_" + runIndex; File file = new File(sFilePath + FileName + ".pdf"); if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } if (!file.exists()) { file.createNewFile(); } fos = new FileOutputStream(file); for (int k = 1; k <= eng.getPageCount(); k++) { fos.write(eng.getPageData(k)); } fos.flush(); fos.close(); } catch (Exception e) { e.printStackTrace(); } finally { if (fos != null) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } fos = null; } } } } /* * Dummy classes to avoid compilation errors. */ private static class ReportProperties { public static final String PAPER_FANFOLD_US = null; public static final String DEFAULT_PAPER_ORIENTATION = null; public void setPaperOrient(String defaultPaperOrientation, String paperFanfoldUs) { } } private static class Engine { public static final int EXPORT_PDF = 1; public Engine(int exportType) { } public static void shutdown() { } public static void stopAll() { } public void setPrompt(Object singleData, int i) { } public byte[] getPageData(int k) { return null; } public int getPageCount() { return 0; } public void execute() { } public ReportProperties getReportProperties() { return null; } public void setConnection(Connection cn) { } public void setReportFile(String reportFile) { } } }

Tengo un archivo rpt, con el cual generaré múltiples informes en formato pdf. Usando la clase Engine desde inet clear reports. El proceso lleva mucho tiempo ya que tengo casi 10000 informes para generar. ¿Puedo utilizar Mutli-thread o algún otro enfoque para acelerar el proceso?

Cualquier ayuda de cómo se puede hacer sería útil

Mi código parcial

//Loops Engine eng = new Engine(Engine.EXPORT_PDF); eng.setReportFile(rpt); //rpt is the report name if (cn.isClosed() || cn == null ) { cn = ds.getConnection(); } eng.setConnection(cn); System.out.println(" After set connection"); eng.setPrompt(data[i], 0); ReportProperties repprop = eng.getReportProperties(); repprop.setPaperOrient(ReportProperties.DEFAULT_PAPER_ORIENTATION, ReportProperties.PAPER_FANFOLD_US); eng.execute(); System.out.println(" After excecute"); try { PDFExportThread pdfExporter = new PDFExportThread(eng, sFileName, sFilePath); pdfExporter.execute(); } catch (Exception e) { e.printStackTrace(); }

PDFExportThread execute

public void execute() throws IOException { FileOutputStream fos = null; try { String FileName = sFileName + "_" + (eng.getPageCount() - 1); File file = new File(sFilePath + FileName + ".pdf"); if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } if (!file.exists()) { file.createNewFile(); } fos = new FileOutputStream(file); for (int k = 1; k <= eng.getPageCount(); k++) { fos.write(eng.getPageData(k)); } fos.flush(); fos.close(); } catch (Exception e) { e.printStackTrace(); } finally { if (fos != null) { fos.close(); fos = null; } } }


Ofreceré esta "respuesta" como una posible solución rápida y sucia para que comiences un esfuerzo de paralelización.

De una manera u otra, vas a construir una granja de renderizado. No creo que haya una manera trivial de hacer esto en Java; Me encantaría que alguien publicara una respuesta que muestre cómo poner en paralelo su ejemplo en unas pocas líneas de código. Pero hasta que eso ocurra, con suerte lo ayudará a progresar.

Tendrás escalas limitadas en la misma instancia de JVM. Pero ... veamos qué tan lejos llegas con eso y ve si ayuda lo suficiente .

Desafío de diseño # 1: reinicio.

Es probable que desee un lugar para guardar el estado de cada uno de sus informes, por ejemplo, "unidades de trabajo".

Desea esto en caso de que necesite reiniciar todo (tal vez su servidor falle) y no desea volver a ejecutar todos los informes hasta el momento.

Hay muchas maneras en que puedes hacer esto; base de datos, verifique si existe un archivo "completado" en su carpeta de informes (no es suficiente para que exista * .pdf, ya que puede estar incompleto ... para xyz_200.pdf podría hacer una xyz_200.done vacía o xyz_200 vacía) .err file para ayudar a volver a ejecutar cualquier problema con los niños ... y cuando codifica esa lógica de manipulación / verificación / inicialización de archivos, parece que puede haber sido más fácil agregar una columna a su base de datos que contiene la lista de trabajo por hacer).

Consideración de diseño n. ° 2: maximización del rendimiento (evitando la sobrecarga).

No desea saturar su sistema y ejecutar mil informes en paralelo. Quizás 10.
Quizás 100.
Probablemente no 5.000.
Tendrá que hacer una investigación de tamaño y ver qué le acerca del 80 al 90% de utilización del sistema.

Consideración de diseño n. ° 3: escala en múltiples servidores

Completamente complejo, fuera del alcance de una respuesta de Stack Exchange. Tendría que crear JVM en varios sistemas que ejecutan algo así como los trabajadores a continuación, y un administrador de informes que puede extraer elementos de una estructura compartida de "colas". De nuevo, una tabla de base de datos es probablemente más fácil que hacer algo. basado en (o una alimentación de red).

Código de muestra

Precaución: Ninguno de estos códigos está bien probado, es casi seguro que tiene una gran cantidad de errores tipográficos, de lógica y de diseño deficiente. Úselo bajo su propio riesgo.

Entonces de todos modos ... quiero darte la idea básica de un corredor de tareas rudimentario. Reemplace su ejemplo "// Loops" en la pregunta con un código como el siguiente:

bucle principal (ejemplo de código original)

Esto es más o menos lo que hizo su código de ejemplo, modificado para llevar la mayor parte del trabajo a ReportWorker (nueva clase, ver a continuación). Muchas cosas parecen estar empaquetadas en el ejemplo de su pregunta original de "// Loop", así que no estoy tratando de realizar una ingeniería inversa.

Sin embargo, no estaba claro de dónde proceden "rpt" y "data [i]", así que recorté algunos datos de prueba.

public class Main { public static boolean complete( String data ) { return false; // for testing nothing is complete. } public static void main(String args[] ) { String data[] = new String[] { "A", "B", "C", "D", "E" }; String rpt = "xyz"; // Loop ReportManager reportMgr = new ReportManager(); // a new helper class (see below), it assigns/monitors work. long startTime = System.currentTimeMillis(); for( int i = 0; i < data.length; ++i ) { // complete is something you should write that knows if a report "unit of work" // finished successfully. if( !complete( data[i] ) ) { reportMgr.assignWork( rpt, data[i] ); // so... where did values for your "rpt" variable come from? } } reportMgr.waitForWorkToFinish(); // out of new work to assign, let''s wait until everything in-flight complete. long endTime = System.currentTimeMillis(); System.out.println("Done. Elapsed time = " + (endTime - startTime)/1000 +" seconds."); } }

ReportManager

Esta clase no es segura para subprocesos, simplemente haga que su bucle original continúe llamando a assignWork () hasta que se quede sin informes para asignar y luego continúe llamándolo hasta que todo el trabajo esté terminado, por ejemplo, waitForWorkToFinish (), como se muestra arriba. (Fwiw, no creo que puedas decir que ninguna de las clases aquí son especialmente seguras para subprocesos).

public class ReportManager { public int polling_delay = 500; // wait 0.5 seconds for testing. //public int polling_delay = 60 * 1000; // wait 1 minute. // not high throughput millions of reports / second, we''ll run at a slower tempo. public int nWorkers = 3; // just 3 for testing. public int assignedCnt = 0; public ReportWorker workers[]; public ReportManager() { // initialize our manager. workers = new ReportWorker[ nWorkers ]; for( int i = 0; i < nWorkers; ++i ) { workers[i] = new ReportWorker( i ); System.out.println("Created worker #"+i); } } private ReportWorker handleWorkerError( int i ) { // something went wrong, update our "report" status as one of the reports failed. System.out.println("handlerWokerError(): failure in "+workers[i]+", resetting worker."); workers[i].teardown(); workers[i] = new ReportWorker( i ); // just replace everything. return workers[i]; // the new worker will, incidentally, be avaialble. } private ReportWorker handleWorkerComplete( int i ) { // this unit of work was completed, update our "report" status tracker as success. System.out.println("handleWorkerComplete(): success in "+workers[i]+", resetting worker."); workers[i].teardown(); workers[i] = new ReportWorker( i ); // just replace everything. return workers[i]; // the new worker will, incidentally, be avaialble. } private int activeWorkerCount() { int activeCnt = 0; for( int i = 0; i < nWorkers; ++i ) { ReportWorker worker = workers[i]; System.out.println("activeWorkerCount() i="+i+", checking worker="+worker); if( worker.hasError() ) { worker = handleWorkerError( i ); } if( worker.isComplete() ) { worker = handleWorkerComplete( i ); } if( worker.isInitialized() || worker.isRunning() ) { ++activeCnt; } } System.out.println("activeWorkerCount() activeCnt="+activeCnt); return activeCnt; } private ReportWorker getAvailableWorker() { // check each worker to see if anybody recently completed... // This (rather lazily) creates completely new ReportWorker instances. // You might want to try pooling (salvaging and reinitializing them) // to see if that helps your performance. System.out.println("/n-----"); ReportWorker firstAvailable = null; for( int i = 0; i < nWorkers; ++i ) { ReportWorker worker = workers[i]; System.out.println("getAvailableWorker(): i="+i+" worker="+worker); if( worker.hasError() ) { worker = handleWorkerError( i ); } if( worker.isComplete() ) { worker = handleWorkerComplete( i ); } if( worker.isAvailable() && firstAvailable==null ) { System.out.println("Apparently worker "+worker+" is ''available''"); firstAvailable = worker; System.out.println("getAvailableWorker(): i="+i+" now firstAvailable = "+firstAvailable); } } return firstAvailable; // May (or may not) be null. } public void assignWork( String rpt, String data ) { ReportWorker worker = getAvailableWorker(); while( worker == null ) { System.out.println("assignWork: No workers available, sleeping for "+polling_delay); try { Thread.sleep( polling_delay ); } catch( InterruptedException e ) { System.out.println("assignWork: sleep interrupted, ignoring exception "+e); } // any workers avaialble now? worker = getAvailableWorker(); } ++assignedCnt; worker.initialize( rpt, data ); // or whatever else you need. System.out.println("assignment #"+assignedCnt+" given to "+worker); Thread t = new Thread( worker ); t.start( ); // that is pretty much it, let it go. } public void waitForWorkToFinish() { int active = activeWorkerCount(); while( active >= 1 ) { System.out.println("waitForWorkToFinish(): #active workers="+active+", waiting..."); // wait a minute.... try { Thread.sleep( polling_delay ); } catch( InterruptedException e ) { System.out.println("assignWork: sleep interrupted, ignoring exception "+e); } active = activeWorkerCount(); } } }

ReportWorker

public class ReportWorker implements Runnable { int test_delay = 10*1000; //sleep for 10 seconds. // (actual code would be generating PDF output) public enum StatusCodes { UNINITIALIZED, INITIALIZED, RUNNING, COMPLETE, ERROR }; int id = -1; StatusCodes status = StatusCodes.UNINITIALIZED; boolean initialized = false; public String rpt = ""; public String data = ""; //Engine eng; //PDFExportThread pdfExporter; //DataSource_type cn; public boolean isInitialized() { return initialized; } public boolean isAvailable() { return status == StatusCodes.UNINITIALIZED; } public boolean isRunning() { return status == StatusCodes.RUNNING; } public boolean isComplete() { return status == StatusCodes.COMPLETE; } public boolean hasError() { return status == StatusCodes.ERROR; } public ReportWorker( int id ) { this.id = id; } public String toString( ) { return "ReportWorker."+id+"("+status+")/"+rpt+"/"+data; } // the example code doesn''t make clear if there is a relationship between rpt & data[i]. public void initialize( String rpt, String data /* data[i] in original code */ ) { try { this.rpt = rpt; this.data = data; /* uncomment this part where you have the various classes availble. * I have it commented out for testing. cn = ds.getConnection(); Engine eng = new Engine(Engine.EXPORT_PDF); eng.setReportFile(rpt); //rpt is the report name eng.setConnection(cn); eng.setPrompt(data, 0); ReportProperties repprop = eng.getReportProperties(); repprop.setPaperOrient(ReportProperties.DEFAULT_PAPER_ORIENTATION, ReportProperties.PAPER_FANFOLD_US); */ status = StatusCodes.INITIALIZED; initialized = true; // want this true even if we''re running. } catch( Exception e ) { status = StatusCodes.ERROR; throw new RuntimeException("initialze(rpt="+rpt+", data="+data+")", e); } } public void run() { status = StatusCodes.RUNNING; System.out.println("run().BEGIN: "+this); try { // delay for testing. try { Thread.sleep( test_delay ); } catch( InterruptedException e ) { System.out.println(this+".run(): test interrupted, ignoring "+e); } /* uncomment this part where you have the various classes availble. * I have it commented out for testing. eng.execute(); PDFExportThread pdfExporter = new PDFExportThread(eng, sFileName, sFilePath); pdfExporter.execute(); */ status = StatusCodes.COMPLETE; System.out.println("run().END: "+this); } catch( Exception e ) { System.out.println("run().ERROR: "+this); status = StatusCodes.ERROR; throw new RuntimeException("run(rpt="+rpt+", data="+data+")", e); } } public void teardown() { if( ! isInitialized() || isRunning() ) { System.out.println("Warning: ReportWorker.teardown() called but I am uninitailzied or running."); // should never happen, fatal enough to throw an exception? } /* commented out for testing. try { cn.close(); } catch( Exception e ) { System.out.println("Warning: ReportWorker.teardown() ignoring error on connection close: "+e); } cn = null; */ // any need to close things on eng? // any need to close things on pdfExporter? } }