并行执行shell进程

是否有一个工具可以在Windowsbatch file中并行执行多个进程? 我发现了一些有趣的工具( 并行和PPSS ),但是,我需要一个Windows平台的工具。

奖金:如果该工具还允许在几台机器之间以简单的方式分配进程,使用PsExec远程运行进程,那将是一件好事 。

例如:我想在下面的循环

for %F in (*.*) do processFile.exe %F 

并行运行有限数量的processFile.exe实例以利用多核CPU。

Linux下的GNU xargs有一个“-P n”开关来并行启动“n”进程。

也许cygwin / mingw构build的xargs也支持这个?

那么你可以使用:

 xargs -P 4 processFile < fileList 

虽然没有花哨的多节点进程产卵。

编辑我修改了脚本来select显示每个进程的输出

这是一个本地批处理解决scheme,可以并行运行一系列命令,一次不会启动n个以上的进程。

它甚至有内置的机制,通过PSEXEC将进程分配给特定的CPU或远程机器,但是我没有testing过这个function。

使这项工作的诀窍是通过CMD进程启动每个命令,将标准输出或未定义的句柄redirect到locking文件。 该进程将保持对文件的排它锁,直到它终止。 无论进程如何终止(正常退出,崩溃,死亡进程)都无关紧要,locking将尽快释放。

主脚本可以通过尝试redirect到相同的locking文件来testing进程是否仍处于活动状态。 如果进程仍处于活动状态,则redirect将失败,如果终止则成功。

默认情况下,脚本会忽略每个进程的输出。 如果以/O选项作为第一个参数启动,那么它会显示每个进程的输出,而不交叉。

我的演示将过程限制设置为4,并简单地运行一系列不同长度的PING命令。

我已经在XP,Vista和Windows 7上testing过了。

 @echo off setlocal enableDelayedExpansion :: Display the output of each process if the /O option is used :: else ignore the output of each process if /i "%~1" equ "/O" ( set "lockHandle=1" set "showOutput=1" ) else ( set "lockHandle=1^>nul 9" set "showOutput=" ) :: List of commands goes here. Each command is prefixed with ::: ::: ping /n 05 ::1 ::: ping /n 20 ::1 ::: ping /n 10 ::1 ::: ping /n 15 ::1 ::: ping /n 07 ::1 ::: ping /n 05 ::1 ::: ping /n 20 ::1 ::: ping /n 10 ::1 ::: ping /n 15 ::1 ::: ping /n 07 ::1 :: Define the maximum number of parallel processes to run. :: Each process number can optionally be assigned to a particular server :: and/or cpu via psexec specs (untested). set "maxProc=4" :: Optional - Define CPU targets in terms of PSEXEC specs :: (everything but the command) :: :: If a cpu is not defined for a proc, then it will be run on the local machine. :: I haven't tested this feature, but it seems like it should work. :: :: set cpu1=psexec \\server1 ... :: set cpu2=psexec \\server1 ... :: set cpu3=psexec \\server2 ... :: etc. :: For this demo force all cpu specs to undefined (local machine) for /l %%N in (1 1 %maxProc%) do set "cpu%%N=" :: Get a unique base lock name for this particular instantiation. :: Incorporate a timestamp from WMIC if possible, but don't fail if :: WMIC not available. Also incorporate a random number. set "lock=" for /f "skip=1 delims=-+ " %%T in ('2^>nul wmic os get localdatetime') do ( set "lock=%%T" goto :break ) :break set "lock=%temp%\lock%lock%_%random%_" :: Initialize the counters set /a "startCount=0, endCount=0" :: Clear any existing end flags for /l %%N in (1 1 %maxProc%) do set "endProc%%N=" :: Launch the commands in a loop set launch=1 for /f "tokens=* delims=:" %%A in ('findstr /b ":::" "%~f0"') do ( if !startCount! lss %maxProc% ( set /a "startCount+=1, nextProc=startCount" ) else ( call :wait ) set cmd!nextProc!=%%A if defined showOutput echo ------------------------------------------------------------------------------- echo !time! - proc!nextProc!: starting %%A 2>nul del %lock%!nextProc! %= Redirect the lock handle to the lock file. The CMD process will =% %= maintain an exclusive lock on the lock file until the process ends. =% start /b "" cmd /c %lockHandle%^>"%lock%!nextProc!" 2^>^&1 !cpu%%N! %%A ) set "launch=" :wait :: Wait for procs to finish in a loop :: If still launching then return as soon as a proc ends :: else wait for all procs to finish :: redirect stderr to null to suppress any error message if redirection :: within the loop fails. for /l %%N in (1 1 %startCount%) do 2>nul ( %= Redirect an unused file handle to the lock file. If the process is =% %= still running then redirection will fail and the IF body will not run =% if not defined endProc%%N if exist "%lock%%%N" 9>>"%lock%%%N" ( %= Made it inside the IF body so the process must have finished =% if defined showOutput echo =============================================================================== echo !time! - proc%%N: finished !cmd%%N! if defined showOutput type "%lock%%%N" if defined launch ( set nextProc=%%N exit /b ) set /a "endCount+=1, endProc%%N=1" ) ) if %endCount% lss %startCount% ( 1>nul 2>nul ping /n 2 ::1 goto :wait ) 2>nul del %lock%* if defined showOutput echo =============================================================================== echo Thats all folks! 

这是从忽略过程输出的样本运行中输出的

 12:24:07.52 - proc1: starting ping /n 05 ::1 12:24:07.52 - proc2: starting ping /n 20 ::1 12:24:07.53 - proc3: starting ping /n 10 ::1 12:24:07.54 - proc4: starting ping /n 15 ::1 12:24:11.60 - proc1: finished ping /n 05 ::1 12:24:11.60 - proc1: starting ping /n 07 ::1 12:24:16.66 - proc3: finished ping /n 10 ::1 12:24:16.66 - proc3: starting ping /n 05 ::1 12:24:17.68 - proc1: finished ping /n 07 ::1 12:24:17.68 - proc1: starting ping /n 20 ::1 12:24:20.72 - proc3: finished ping /n 05 ::1 12:24:20.72 - proc3: starting ping /n 10 ::1 12:24:21.75 - proc4: finished ping /n 15 ::1 12:24:21.75 - proc4: starting ping /n 15 ::1 12:24:26.82 - proc2: finished ping /n 20 ::1 12:24:26.82 - proc2: starting ping /n 07 ::1 12:24:29.86 - proc3: finished ping /n 10 ::1 12:24:32.89 - proc2: finished ping /n 07 ::1 12:24:35.92 - proc4: finished ping /n 15 ::1 12:24:36.93 - proc1: finished ping /n 20 ::1 Thats all folks 

如果使用显示过程输出的/O选项运行,则输出如下

 ------------------------------------------------------------------------------- 12:24:51.02 - proc1: starting ping /n 05 ::1 ------------------------------------------------------------------------------- 12:24:51.02 - proc2: starting ping /n 20 ::1 ------------------------------------------------------------------------------- 12:24:51.03 - proc3: starting ping /n 10 ::1 ------------------------------------------------------------------------------- 12:24:51.04 - proc4: starting ping /n 15 ::1 =============================================================================== 12:24:55.10 - proc1: finished ping /n 05 ::1 Pinging ::1 with 32 bytes of data: Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Ping statistics for ::1: Packets: Sent = 5, Received = 5, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 0ms, Maximum = 0ms, Average = 0ms ------------------------------------------------------------------------------- 12:24:55.10 - proc1: starting ping /n 07 ::1 =============================================================================== 12:25:00.17 - proc3: finished ping /n 10 ::1 Pinging ::1 with 32 bytes of data: Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Ping statistics for ::1: Packets: Sent = 10, Received = 10, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 0ms, Maximum = 0ms, Average = 0ms ------------------------------------------------------------------------------- 12:25:00.19 - proc3: starting ping /n 05 ::1 =============================================================================== 12:25:01.22 - proc1: finished ping /n 07 ::1 Pinging ::1 with 32 bytes of data: Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Ping statistics for ::1: Packets: Sent = 7, Received = 7, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 0ms, Maximum = 0ms, Average = 0ms ------------------------------------------------------------------------------- 12:25:01.23 - proc1: starting ping /n 20 ::1 =============================================================================== 12:25:04.27 - proc3: finished ping /n 05 ::1 Pinging ::1 with 32 bytes of data: Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Ping statistics for ::1: Packets: Sent = 5, Received = 5, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 0ms, Maximum = 0ms, Average = 0ms ------------------------------------------------------------------------------- 12:25:04.28 - proc3: starting ping /n 10 ::1 =============================================================================== 12:25:05.30 - proc4: finished ping /n 15 ::1 Pinging ::1 with 32 bytes of data: Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Ping statistics for ::1: Packets: Sent = 15, Received = 15, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 0ms, Maximum = 0ms, Average = 0ms ------------------------------------------------------------------------------- 12:25:05.32 - proc4: starting ping /n 15 ::1 =============================================================================== 12:25:10.38 - proc2: finished ping /n 20 ::1 Pinging ::1 with 32 bytes of data: Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Ping statistics for ::1: Packets: Sent = 20, Received = 20, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 0ms, Maximum = 0ms, Average = 0ms ------------------------------------------------------------------------------- 12:25:10.40 - proc2: starting ping /n 07 ::1 =============================================================================== 12:25:13.44 - proc3: finished ping /n 10 ::1 Pinging ::1 with 32 bytes of data: Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Ping statistics for ::1: Packets: Sent = 10, Received = 10, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 0ms, Maximum = 0ms, Average = 0ms =============================================================================== 12:25:16.48 - proc2: finished ping /n 07 ::1 Pinging ::1 with 32 bytes of data: Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Ping statistics for ::1: Packets: Sent = 7, Received = 7, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 0ms, Maximum = 0ms, Average = 0ms =============================================================================== 12:25:19.52 - proc4: finished ping /n 15 ::1 Pinging ::1 with 32 bytes of data: Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Ping statistics for ::1: Packets: Sent = 15, Received = 15, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 0ms, Maximum = 0ms, Average = 0ms =============================================================================== 12:25:20.54 - proc1: finished ping /n 20 ::1 Pinging ::1 with 32 bytes of data: Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Reply from ::1: time<1ms Ping statistics for ::1: Packets: Sent = 20, Received = 20, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 0ms, Maximum = 0ms, Average = 0ms =============================================================================== Thats all folks 

尝试start

 start "title of the process" "P:\ath\to.exe" 

它会打开一个带有给定标题的新窗口并执行BAT,CMD或EXE文件。 您还可以设置优先级,设置相同的环境等

不能执行的文件与相关程序一起打开。

进一步阅读:开始 – >运行

 cmd /k start /? 

至less从WinME开始是可用的。

祝你好运!

听起来更像你想使用Powershell 2.但是,你可以通过使用start产生新的cmd窗口(或其他进程),也请参阅此答案。 尽pipe您可能需要使用一些其他工具和一些小技巧来创build“进程池”(一次最多只能运行n个实例)。 你可以通过使用tasklist /im计算后者,并计算已经存在的数量( for循环或wc ,如果适用的话),然后等待( ping -n 2 ::1 >nul 2>&1 )并再次检查你是否可以产生一个新的过程。

我已经拼凑了一点这个testing批次:

 @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 /c /v ""`) do set INSTANCES=%%t goto :eof 

它产生了最多四个并行执行并最小化的新进程。 等待时间可能需要调整,具体取决于每个进程的运行时间以及运行时间。 您可能还需要调整任务列表正在查找的进程名称,如果您正在执行其他任务。

尽pipe如此,没有办法正确地计数这批产生的进程。 一种方法是在批处理开始时创build一个随机数( %RANDOM% ),并创build一个辅助批处理(或者派生处理程序),但是可以将其窗口标题设置为一个参数:

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

这将是一个简单的批处理,它将标题设置为第一个参数,然后以第三个参数运行第二个参数。 然后,您可以通过仅select具有指定窗口标题( tasklist /fi "windowtitle eq ..." )的进程来过滤任务tasklist /fi "windowtitle eq ..." 。 这应该工作相当可靠,并防止太多的误报。 如果您仍然有一些实例正在运行,那么searchcmd.exe将是一个坏主意,因为这会限制您的工作进程池。

您可以使用%NUMBER_OF_PROCESSORS%来创build产生多less实例的合理默认值。

你也可以很容易地使用这个方法来使用psexec远程产生进程(但是由于你必须在另一台机器上拥有pipe理员权限以及在批处理中提供密码,所以不会非常可行)。 不过,您必须使用进程名称进行筛选。