Comando batch di Windows FOR con multithread


11

sai se esiste un modo semplice per eseguire il comando FOR nel file batch su più thread? Qual è il punto di avere 4 core se non riesco a eseguire i miei compiti in 4 thread paralleli?

Ad esempio, se sto ottimizzando i PNG con PNGOUT, il comando che vorrei usare è

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

Ma questo è un compito altamente paralellizzabile in cui i compiti secondari non dipendono affatto l'uno dall'altro.

Per eseguirlo in 4 "code" scriverei qualcosa del genere

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

Devo scrivere la mia app for-like che sarebbe in grado di farlo o è disponibile una soluzione gratuita?


controllare la risposta seguente per utilizzare strumento esterno: [ stackoverflow.com/a/12041213/365229][1] [1]: stackoverflow.com/a/12041213/365229
Behrouz.M

Risposte:


13

Ho scritto un file batch che esegue solo un numero massimo di comandi qualche tempo fa su StackTranslate.it: Esecuzione parallela di processi 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 massimo di quattro nuovi processi che vengono eseguiti in parallelo e ridotti al minimo. Il tempo di attesa deve essere modificato probabilmente, a seconda di quanto fa ogni processo e per quanto tempo è in esecuzione. Probabilmente dovrai anche adattare il nome del processo per cui l'elenco di attività sta cercando se stai facendo qualcos'altro.

Tuttavia, non è possibile contare correttamente i processi generati da questo batch. Un modo sarebbe quello di creare un numero casuale all'inizio del batch ( %RANDOM%) e creare un batch helper che esegue l'elaborazione (o genera il programma di elaborazione) ma che può impostare il titolo della finestra su un parametro:

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

Questo sarebbe un semplice batch che imposta il titolo sul primo parametro e quindi esegue il secondo parametro con il terzo come argomento. È quindi possibile filtrare nell'elenco attività selezionando solo i processi con il titolo della finestra specificato ( tasklist /fi "windowtitle eq ..."). Questo dovrebbe funzionare abbastanza affidabile e prevenire troppi falsi positivi. La ricerca cmd.exesarebbe una cattiva idea se hai ancora alcune istanze in esecuzione, in quanto ciò limita il tuo pool di processi di lavoro.

Puoi usare %NUMBER_OF_PROCESSORS%per creare un ragionevole valore predefinito di quante istanze spawnare.

Puoi anche facilmente adattare questo per utilizzare psexecper generare i processi in remoto (ma non sarebbe molto praticabile in quanto devi avere i privilegi di amministratore sull'altro computer e fornire la password nel batch). Tuttavia, dovresti usare i nomi dei processi per filtrare.


questa è una seria magia nera in lotti! Vorrei poter votare più volte!
Axarydax,

No, è roba abbastanza semplice una volta che hai capito :-)
Joey,

Il comando 'wc' non è disponibile nella mia riga di comando Win10. Cosa posso usare altro?
PeterCo

1
@PeterCo: find /c /v "".
Joey,

1

I file batch sono per uno scripting estremamente semplice e non supportano alcun tipo di multithreading. Dovresti scrivere la tua utility per fare ciò che vuoi realizzare.

In alternativa, Windows PowerShell potrebbe fornire più funzionalità per avvicinarti al tuo obiettivo.

Se si desidera semplicemente eseguire più operazioni contemporaneamente, è possibile utilizzare il comando start per avviare l'utilità PNGOUT in una nuova finestra. Il ciclo FOR continuerà quindi senza attendere il completamento di ciascuna operazione.

La linea modificata sarebbe simile a questa:

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

Tuttavia, nota che questo avvierà PNGOUT per TUTTI i file nella directory allo stesso tempo, il che probabilmente non è desiderabile.


Questo è un approccio ingenuo e, come dici tu, probabilmente non è desiderabile. Volete solo avviare tutti i processi quanti sono i core. Se hai 4 core e 1.000 file, vuoi davvero elaborarne solo 4 alla volta fino a quando non vengono elaborati tutti i 1.000. Se si tenta di elaborare tutti i 1.000 contemporaneamente su 4 core, il computer rallenterà fino a una scansione inutile.
Adisak,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.