Commande par lots Windows FOR multithread

10

savez-vous s'il existe un moyen simple d'exécuter la commande FOR dans un fichier de commandes sur plusieurs threads? Quel est l'intérêt d'avoir 4 cœurs si je ne peux pas exécuter mes tâches dans 4 threads parallèles?

Par exemple, si j'optimise les PNG avec PNGOUT, la commande que j'utiliserais est

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

Mais il s’agit là d’une tâche hautement paralisable dans laquelle les sous-tâches ne dépendent pas les unes des autres.

Pour exécuter ceci en 4 'files d'attente' j'écrirais quelque chose comme

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

Dois-je écrire ma propre application semblable à celle qui pourrait le faire ou existe-t-il une solution gratuite disponible?

Axarydax
la source
Vérifiez la réponse suivante à l'aide d'un outil externe: [ stackoverflow.com/a/12041213/365229][1] [1]: stackoverflow.com/a/12041213/365229
Behrouz.M

Réponses:

12

J'ai écrit un fichier de commandes qui n'exécute qu'un nombre maximal de commandes il y a quelque temps sur Stack Overflow: Exécution parallèle de processus 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

Il génère un maximum de quatre nouveaux processus qui s'exécutent en parallèle et sont minimisés. Le temps d’attente doit probablement être ajusté en fonction du nombre et de la durée de chaque processus. Vous devrez probablement aussi ajuster le nom du processus pour la liste de tâches à la recherche si vous faites autre chose.

Cependant, il n’existe aucun moyen de compter correctement les processus générés par ce lot. Une solution serait de créer un nombre aléatoire au début de batch ( %RANDOM%) et de créer un lot auxiliaire qui effectue le traitement (ou génère le programme de traitement) mais qui peut définir le titre de la fenêtre sur un paramètre:

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

Ce serait un simple lot qui définit son titre sur le premier paramètre, puis exécute le second paramètre avec le troisième comme argument. Vous pouvez ensuite filtrer dans la liste des tâches en sélectionnant uniquement les processus ayant le titre de fenêtre spécifié ( tasklist /fi "windowtitle eq ..."). Cela devrait fonctionner assez fiable et éviter trop de faux positifs. La recherche de ce cmd.exeserait une mauvaise idée si vous avez toujours des instances en cours d'exécution, car cela limite votre pool de processus de travail.

Vous pouvez utiliser %NUMBER_OF_PROCESSORS%pour créer une valeur par défaut raisonnable du nombre d'instances à générer.

Vous pouvez également facilement l'adapter pour utiliser psexecles processus à distance (mais ce ne serait pas très viable, car vous devez disposer des privilèges d'administrateur sur l'autre machine et fournir le mot de passe dans le lot). Vous devrez alors utiliser des noms de processus pour le filtrage.

Joey
la source
c'est de la magie noire du lot! J'aimerais pouvoir voter plus de fois!
Axarydax
Nah, c'est assez basique une fois que vous avez compris le principe ;-)
Joey
La commande 'wc' n'est pas disponible dans ma ligne de commande Win10. Que puis-je utiliser d'autre?
PeterCo
1
@PeterCo: find /c /v "".
Joey
1

Les fichiers batch sont destinés à des scripts extrêmement basiques et ne prennent en charge aucun type de multithreading. Vous devrez écrire votre propre utilitaire pour faire ce que vous voulez accomplir.

Sinon, Windows PowerShell peut fournir plus de fonctionnalités pour vous rapprocher de votre objectif.

Si vous voulez simplement exécuter plusieurs opérations en même temps, vous pouvez utiliser la commande start pour lancer l'utilitaire PNGOUT dans une nouvelle fenêtre. La boucle FOR continuera alors sans attendre que chaque opération se termine.

La ligne modifiée ressemblerait à ceci:

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

Cependant, notez que ceci lancera effectivement PNGOUT pour TOUS les fichiers du répertoire en même temps, ce qui n’est probablement pas souhaitable.

Herohtar
la source
C'est une approche naïve et, comme vous l'avez dit, ce n'est probablement pas souhaitable. Vous voulez seulement lancer autant de processus que vous avez de cœurs. Si vous avez 4 cœurs et 1 000 fichiers, vous voulez vraiment en traiter 4 à la fois jusqu'à ce que les 1 000 soient tous traités. Si vous essayez de traiter les 1 000 en même temps sur 4 cœurs, votre ordinateur ralentira au ralenti.
Adisak