¿Cómo puedo get 80,000 descargas en Java simultáneamente?

Estoy clonando una gran muestra de proyectos de GitHub para un estudio empírico. Supongo que será más rápido download los 80,000 proyectos con cierta concurrency, pero eso es mucho para download.

¿Cómo puedo comenzar ~ 1,000 processs y luego comenzar otro después de que termine cada uno? O bien, ¿hay alguna otra manera en que debería hacerlo? ¿Sería malo para los serveres de GitHub download todo esto a una velocidad mayor que la secuencial?

Aquí está el código relevante hasta el momento:

// Create a CountDownLatch that will only reach 0 when all repositories // have been downloaded CountDownLatch doneSignal = new CountDownLatch(numberOfRepositories); // Start the download for each git repository for (String URL : gitURLs) { new Thread(new Worker(doneSignal, URL)).start(); } doneSignal.await(); 

Obrero:

 public class Worker implements Runnable { private final CountDownLatch doneSignal; private final String URL; Worker (CountDownLatch doneSignal, String URL) { this.doneSignal = doneSignal; this.URL = URL; } @Override public void run () { try { // Run the command line process to download ProcessBuilder pb = new ProcessBuilder("git", "clone", "--depth=1", URL, "projects/" + getProjectName(URL)); Process p = pb.start(); p.waitFor(); } catch (Exception e) { e.printStackTrace(); } doneSignal.countDown(); } } 

Es malo para los serveres de Github, pero es aún peor para tu performance. Pruebe tal vez 5 o así en lugar de 1000. Para limitar el código a X hilos paralelos, puede usar un grupo:

 CountDownLatch doneSignal = new CountDownLatch(numberOfRepositories); // Start the download for each git repository ExecutorService pool = Executors.newFixedThreadPool(5); for (String URL : gitURLs) { pool.execute(new Worker(doneSignal, URL)); } pool.shutdown(); doneSignal.await(); 

También funciona sin el pestillo porque puede esperar a que la agrupación quede inactiva, por ejemplo,

 pool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); 

Puede probar Java 8 y parallelStream para realizar múltiples subprocesss de sus descargas

  List<String> gitURLs = new ArrayList<>(); gitURLs.parallelStream().forEach( URL -> { try { // Run the command line process to download ProcessBuilder pb = new ProcessBuilder("git", "clone", "--depth=1", URL, "projects/" + getProjectName(URL)); Process p = pb.start(); p.waitFor(); } catch (Exception e) { e.printStackTrace(); } } ); 

No es necesario usar multi-threading y código Java personalizado para una tarea sencilla como esta. Especialmente porque cada hilo solo genera un process externo usando la CLI. Es una sobreingeniería, y podrías hacer el trabajo más rápido usando algo más simple.

Parece que probablemente ya tenga un file con las URL de todos los proyectos que desea clonar. Utilizaría algunos commands en mi editor de text (Sublime Text) para agregar git clone --depth=1 al comienzo de cada línea y & hasta el final (esto ejecuta un command de forma asincrónica). Si su editor de text no puede hacerlo fácilmente, un pequeño script bash / awk / Perl / Ruby / Python / etc podría hacerlo en no más de unas pocas líneas.

Entonces su list de URL se convierte en … un script de shell válido, ¡que clonará todos los repos en paralelo! Y puedes ejecutarlo como tal.

Sin embargo, tenga en count que, si bien las descargas paralelas lo ayudarán, 1000 es demasiado. Puede experimentar con el número, pero probablemente encontrará que ejecutar más de 20 al mismo time no ayudará.