Comando de lote do Windows FOR multithreaded

11

você sabe se existe uma maneira simples de executar o comando FOR no arquivo em lotes em vários segmentos? Qual é o sentido de ter 4 núcleos se não consigo 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 essa é uma tarefa altamente paralelizável, na qual as subtarefas não dependem uma da outra.

Para executar 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 possa fazer isso ou existe uma solução gratuita disponível?

Axarydax
fonte
verifique resposta folowing a usar ferramenta externa: [ stackoverflow.com/a/12041213/365229][1] [1]: stackoverflow.com/a/12041213/365229
Behrouz.M

Respostas:

13

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

Gera no máximo quatro novos processos que são executados em paralelo e minimizados. Provavelmente, o tempo de espera precisa ser ajustado, dependendo da duração de cada processo e do tempo de execução. Você provavelmente também precisará ajustar o nome do processo para o qual a lista de tarefas está procurando, se estiver fazendo outra coisa.

Entretanto, não há como contar adequadamente os processos gerados por esse lote. Uma maneira seria criar um número aleatório no início do lote ( %RANDOM%) e criar um lote auxiliar que faça o processamento (ou gera o programa de processamento), mas que pode definir o título da janela como um parâmetro:

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

Este seria um lote simples que define seu título para o primeiro parâmetro e, em seguida, executa o segundo parâmetro com o terceiro como argumento. Você pode filtrar a lista de tarefas selecionando apenas processos com o título da janela especificado ( tasklist /fi "windowtitle eq ..."). Isso deve funcionar razoavelmente confiável e evita muitos falsos positivos. Procurar cmd.exeseria uma má ideia se você ainda tiver algumas instâncias em execução, pois isso limita seu conjunto de processos de trabalho.

Você pode usar %NUMBER_OF_PROCESSORS%para criar um padrão sensato de quantas instâncias aparecer.

Você também pode adaptar isso facilmente psexecpara gerar remotamente os processos (mas não seria muito viável, pois você precisa ter privilégios de administrador na outra máquina, além de fornecer a senha no lote). Você precisaria usar nomes de processos para filtrar então.

Joey
fonte
isso é uma mágica séria de um lote preto! Eu gostaria de poder votar mais vezes!
Axarydax
Nah, isso é coisa bastante básico quando você pegar o jeito dele ;-)
Joey
O comando 'wc' não está disponível na minha linha de comando do Win10. O que posso usar mais?
PeterCo 23/01
1
@PeterCo: find /c /v "".
Joey
1

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

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

Se você simplesmente deseja executar várias operações ao mesmo tempo, pode usar o comando start para iniciar o utilitário PNGOUT em uma nova janela. O loop FOR continuará sem aguardar a conclusão de cada operação.

A linha modificada ficaria assim:

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

No entanto, observe que isso efetivamente iniciará o PNGOUT para TODOS os arquivos no diretório ao mesmo tempo, o que provavelmente não é desejável.

Herohtar
fonte
Essa é uma abordagem ingênua e, como você mencionou, provavelmente não é desejável. Você deseja iniciar apenas quantos processos tiver núcleos. Se você possui 4 núcleos e 1.000 arquivos, realmente deseja processar apenas 4 por vez até que todos os 1.000 sejam processados. Se você tentar processar todos os 1.000 de uma vez em quatro núcleos, o computador ficará lento para um rastreamento inútil.
Adisak