Comando batch do Windows FOR multithread

9

você sabe se existe uma maneira simples de executar o comando FOR no arquivo em lote em vários segmentos? Qual é o sentido de ter 4 núcleos se não posso executar minhas tarefas em 4 threads paralelos?

Por exemplo, se eu estiver otimizando PNGs com PNGOUT, o comando que eu usaria é

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

Mas esta é uma tarefa altamente paralelizável na qual as sub-tarefas não dependem umas das outras.

Para rodar isso em 4 'filas' eu escreveria algo como

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

Preciso escrever meu próprio aplicativo semelhante que poderia fazer isso ou há solução gratuita disponível?

    
por Axarydax 12.01.2011 / 13:55

2 respostas

10

Eu escrevi um arquivo em lotes que executa apenas um número máximo de comandos um tempo atrás no Stack Overflow: Execução paralela de processos 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

It spawns a maximum of four new processes that execute in parallel and minimized. Wait time needs to be adjusted probably, depending on how much each process does and how long it is running. You probably also need to adjust the process name for which tasklist is looking if you're doing something else.

There is no way to properly count the processes that are spawned by this batch, though. One way would be to create a random number at the start of the batch (%RANDOM%) and create a helper batch that does the processing (or spawns the processing program) but which can set its window title to a parameter:

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

This would be a simple batch that sets its title to the first parameter and then runs the second parameter with the third as argument. You can then filter in tasklist by selecting only processes with the specified window title (tasklist /fi "windowtitle eq ..."). This should work fairly reliable and prevents too many false positives. Searching for cmd.exe would be a bad idea if you still have some instances running, as that limits your pool of worker processes.

You can use %NUMBER_OF_PROCESSORS% to create a sensible default of how many instances to spawn.

You can also easily adapt this to use psexec to spawn the processes remotely (but wouldn't be very viable as you have to have admin privileges on the other machine as well as provide the password in the batch). You would have to use process names for filtering then, though.

    
por 25.01.2011 / 14:23
1

Os arquivos em lote são para scripts extremamente básicos e não suportam nenhum tipo de multithreading. Você precisaria escrever seu próprio utilitário para fazer o que você deseja realizar.

Como alternativa, o Windows PowerShell pode fornecer mais recursos para você se aproximar de sua meta.

Se você simplesmente quiser executar várias operações ao mesmo tempo, poderá usar o comando start para iniciar o utilitário PNGOUT em uma nova janela. O loop FOR continuará então sem esperar que cada operação seja concluída.

A linha modificada ficaria assim:

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

No entanto, note que isso irá efetivamente lançar o PNGOUT para ALL os arquivos no diretório ao mesmo tempo, o que provavelmente não é desejável.

    
por 13.01.2011 / 17:01