并行执行 shell 命令,但限制作业(没有 Cygwin 的 Windows)



这就是我要做的。 假设我有一个名为myprogram.exe的程序,我必须执行 1000 次。

在Windows下,我通常可以做一些简单的事情,比如:

for /L %n in (1,1,1000) do start /myfolder/myprogram.exe

但是,假设我只有 5 个 CPU 线程可以用于运行 1000 个myprogram.exe实例,这样我只启动 5 个,然后当其中一个完成时启动另一个,依此类推,直到整个 1000 个结束。

在Linux下并使用GNU Parallel,我可以简单地做:

seq 1000 | parallel -N0 -j5 "nohup myprogram.exe"

我怎样才能在 Windows 命令行中实现类似的东西?请注意,在我的情况下,使用Cygwin不是一个选项,因此在Windows下诉诸xargs和GNU Parallel也不是选项。

这是一种方法,通过使用powershell进行进程计数。 并使用简单的set /a作为计数器。

@echo off
setlocal enabledelayedexpansion
set /a cnt=0
:counter
if !cnt! lss 1000 (
for /F "tokens=*" %%i in ('powershell ^(Get-Process -Name 'myprogram'^).count') do set proc=%%i
if !proc! lss 5 (
start "C:myfoldermyprogram.exe"
set /a cnt+=1
)
goto :counter
)

如果您想查看计数,可以在goto :counter之前在行中添加echo !cnt!

它可以在不使用delayedexpansion的情况下完成,但我更喜欢在这里使用它。

这将并行运行五个进程。每次其中一个完成时,下一个进程就会开始(所以总是有 5 个,直到它们全部完成(

@ECHO off
setlocal enabledelayedexpansion
set bunch=5
for /l %%a in (1,1,1000) do (
call :loop 
echo processing: %%a
start "MyCommand" cmd /c timeout !random:~-1!
)
call :loop
goto :eof
:loop  REM waits for available slot
for /f %%x in ('tasklist /fi "windowtitle eq MyCommand"  ^| find /c "cmd.exe"') do set x=%%x
if %x% geq %bunch% goto :loop
goto :eof

/min开关添加到start以最大程度地减少启动的进程。
给他们一个独特的窗口标题(MyCommand这里(以便能够计算它们。
cmd /c timeout !random:~-1!替换为实际命令。

编辑一个稍微修改过的脚本,如果myprogram是一个 GUI,它可能工作得更好(上面的脚本在 CLI 应用程序中会更好地工作(:

@ECHO off
setlocal enabledelayedexpansion
set bunch=5
for /l %%a in (1,1,100) do (
call :loop 
echo processing: %%a
start notepad.exe
)
call :loop
goto :eof
:loop  REM waits for available slot
for /f %%x in ('tasklist /fi "imagename eq Notepad.exe"^|find /c "."') do set x=%%x
if %x% geq %bunch% goto :loop
goto :eof

最新更新