Comando por lotes de Windows multiproceso

11

¿sabe si hay una manera simple de ejecutar el comando FOR en un archivo por lotes en varios subprocesos? ¿Cuál es el punto de tener 4 núcleos si no puedo ejecutar mis tareas en 4 hilos paralelos?

Por ejemplo, si estoy optimizando PNG con PNGOUT, el comando que usaría es

for %i in (*.png) do pngout "%i"

Pero esta es una tarea altamente paralelizable en la que las subtareas no dependen entre sí en absoluto.

Para ejecutar esto en 4 'colas', escribiría algo como

for -thread 4 %i in (*.png) do pngout "%i"

¿Necesito escribir mi propia aplicación similar que pueda hacer esto o hay una solución gratuita disponible?

Axarydax
fuente
verifique la siguiente respuesta para usar una herramienta externa: [ stackoverflow.com/a/12041213/365229font>[1] [1]: stackoverflow.com/a/12041213/365229
Behrouz.M

Respuestas:

13

Hace un tiempo escribí un archivo por lotes que ejecuta solo un número máximo de comandos en Desbordamiento de pila: ejecución paralela de procesos de shell :

@echo off
for /l %%i in (1,1,20) do call :loop %%i
goto :eof

:loop
call :checkinstances
if %INSTANCES% LSS 5 (
    rem just a dummy program that waits instead of doing useful stuff
    rem but suffices for now
    echo Starting processing instance for %1
    start /min wait.exe 5 sec
    goto :eof
)
rem wait a second, can be adjusted with -w (-n 2 because the first ping returns immediately;
rem otherwise just use an address that's unused and -n 1)
echo Waiting for instances to close ...
ping -n 2 ::1 >nul 2>&1
rem jump back to see whether we can spawn a new process now
goto loop
goto :eof

:checkinstances
rem this could probably be done better. But INSTANCES should contain the number of running instances afterwards.
for /f "usebackq" %%t in (`tasklist /fo csv /fi "imagename eq wait.exe"^|find /v /c ""`) do set INSTANCES=%%t
goto :eof

Genera un máximo de cuatro procesos nuevos que se ejecutan en paralelo y minimizados. El tiempo de espera debe ajustarse probablemente, dependiendo de cuánto haga cada proceso y cuánto tiempo se esté ejecutando. Probablemente también necesite ajustar el nombre del proceso para el que se está buscando la lista de tareas si está haciendo otra cosa.

Sin embargo, no hay forma de contar correctamente los procesos generados por este lote. Una forma sería crear un número aleatorio al comienzo del lote ( %RANDOM%) y crear un lote auxiliar que realice el procesamiento (o genere el programa de procesamiento) pero que pueda establecer el título de su ventana en un parámetro:

@echo off
title %1
"%2" "%3"

Este sería un lote simple que establece su título para el primer parámetro y luego ejecuta el segundo parámetro con el tercero como argumento. Luego puede filtrar en la lista de tareas seleccionando solo procesos con el título de ventana especificado ( tasklist /fi "windowtitle eq ..."). Esto debería funcionar de manera bastante confiable y evita demasiados falsos positivos. Buscar cmd.exesería una mala idea si todavía tiene algunas instancias en ejecución, ya que eso limita su grupo de procesos de trabajo.

Puede usar %NUMBER_OF_PROCESSORS%para crear un valor predeterminado razonable de cuántas instancias generar.

También puede adaptarlo fácilmente para usarlo psexecpara generar los procesos de forma remota (pero no sería muy viable ya que debe tener privilegios de administrador en la otra máquina y proporcionar la contraseña en el lote). Sin embargo, tendría que usar nombres de proceso para filtrar.

Joey
fuente
¡Esto es algo de magia negra seria! ¡Ojalá pudiera votar más veces!
Axarydax
No, eso es bastante básico una vez que lo dominas ;-)
Joey
El comando 'wc' no está disponible en mi línea de comandos de Win10. ¿Qué puedo usar más?
PeterCo
1
@PeterCo: find /c /v "".
Joey el
1

Los archivos por lotes son para secuencias de comandos extremadamente básicas y no admiten ningún tipo de subprocesamiento múltiple. Tendría que escribir su propia utilidad para hacer lo que desea lograr.

Alternativamente, Windows PowerShell puede proporcionar más capacidades para acercarte a tu objetivo.

Si simplemente desea ejecutar varias operaciones al mismo tiempo, puede usar el comando start para iniciar la utilidad PNGOUT en una nueva ventana. El bucle FOR continuará sin esperar a que finalice cada operación.

La línea modificada se vería así:

for %i in (*.png) do start pngout "%i"

Sin embargo, tenga en cuenta que esto lanzará efectivamente PNGOUT para TODOS los archivos en el directorio al mismo tiempo, lo que probablemente no sea deseable.

Herohtar
fuente
Este es un enfoque ingenuo y, como mencionas, probablemente no sea deseable. Solo desea iniciar tantos procesos como núcleos tenga. Si tiene 4 núcleos y 1,000 archivos, realmente desea procesar solo 4 a la vez hasta que se procesen los 1,000. Si intenta procesar los 1,000 a la vez en 4 núcleos, su computadora se ralentizará a un rastreo inútil.
Adisak