bat文件中的并行处理for循环

时间:2016-07-20 20:36:18

标签: batch-file

我想要一个批处理文件来进行并行处理。我有一个storedprocedure,它返回1000多条记录(具有唯一的rowid列以及其他信息)。尽管每行都可以正常工作。但是,完成1000个循环需要很长时间。有没有办法并行运行两个循环而不重叠或必须维护单独的批处理文件。这可以通过一个.bat文件来实现。

工作代码:

@echo off
setlocal EnableExtensions
set ListFile=%TEMP%\StudentList.tmp
Set varServerPath=http://xyz/ReportServer

sqlcmd -Q "exec dbo.Storedproc_StudentList" -S ServerName -d DatabaseName >"%ListFile%" 2>nul

if exist "%ListFile%" (
   for /F "usebackq tokens=1,2,3,4 skip=2 delims=', " %%A in ("%ListFile%") do (
        echo Processing StudentID %%A and SubjectID %%B ...
        if not exist "%%D" mkdir "%%D"
        rs -i C:\ReportRender\Student.rss -s%varServerPath% -e Exec2005 -v StudentID="%%A" -v SubjectID="%%B" -v vOutputFilePath="%%C"  -v vReportPath="/Student Reports/ReportName.rdl" -l 900 
    )
del "%ListFile%"
)
exit

我尝试过做两个for循环,一个从1到200,另一个从201到400等等......但似乎我走错了轨道。它不起作用,请建议。

    @echo off
setlocal EnableExtensions
set ListFile=%TEMP%\StudentList.tmp
Set varServerPath=http://xyz/ReportServer

sqlcmd -Q "exec dbo.Storedproc_StudentList" -S ServerName -d DatabaseName >"%ListFile%" 2>nul

if exist "%ListFile%" (
    for /F "usebackq tokens=1,2,3,4 skip=2 delims=', " %%A in ("%ListFile%") do (

            for /L %%A in(1,1,200) do (
            echo Processing StudentID %%A and SubjectID %%B ...
            if not exist "%%D" mkdir "%%D"
            rs -i C:\ReportRender\Student.rss -s%varServerPath% -e Exec2005 -v StudentID="%%A" -v SubjectID="%%B" -v vOutputFilePath="%%C"  -v vReportPath="/Student Reports/ReportName.rdl" -l 900 
            )

            for /L %%A in(201,1,400) do (
            echo Processing StudentID %%A and SubjectID %%B ...
            if not exist "%%D" mkdir "%%D"
            rs -i C:\ReportRender\Student.rss -s%varServerPath% -e Exec2005 -v StudentID="%%A" -v SubjectID="%%B" -v vOutputFilePath="%%C"  -v vReportPath="/Student Reports/ReportName.rdl" -l 900 
            )

    )
del "%ListFile%"
)
exit

谢谢,

1 个答案:

答案 0 :(得分:1)

你的做法是错误的。您正在为%ListFile%中的每条记录执行for /L %%A in (1,1,200) ...for /L %%A in (201,1,400) ... 。您需要将%ListFile%中的记录分发到两个并行进程中。虽然这可以在200个记录的组中完成,但逐个执行此操作要简单得多。此外,在批处理文件中拥有并行进程的唯一方法是通过start命令或使用|管道。在这种情况下,您希望分发几个输入记录,这些记录将由两个“输出进程”读取(和处理),因此管道方法更简单。

@echo off
setlocal EnableDelayedExpansion

if "%1" neq "" goto %1

set ListFile=%TEMP%\StudentList.tmp
Set varServerPath=http://xyz/ReportServer

sqlcmd -Q "exec dbo.Storedproc_StudentList" -S ServerName -d DatabaseName >"%ListFile%" 2>nul

if not exist "%ListFile%" exit

set numProcs=2
( "%~F0" Input  |  "%~F0" Output ) 2>&1  |  "%~F0" Output
del "%ListFile%"
exit


:Input
set i=0
for /F "usebackq tokens=1,2,3,4 skip=2 delims=', " %%A in ("%ListFile%") do (
   set /A i+=1, proc=i%%numProcs
   if !proc! equ 1 (
      echo %%A %%B %%C %%D
   ) else (
      >&2 echo %%A %%B %%C %%D
   )
)
exit /B


:Output
for /F "tokens=1-4" %%A in ('findstr "^"') do (
   echo Processing StudentID %%A and SubjectID %%B ...
   if not exist "%%D" mkdir "%%D"
   rs -i C:\ReportRender\Student.rss -s%varServerPath% -e Exec2005 -v StudentID="%%A" -v SubjectID="%%B" -v vOutputFilePath="%%C"  -v vReportPath="/Student Reports/ReportName.rdl" -l 900 
)
exit /B
  • :Input部分只是将“%ListFile%”记录逐个分发到Stdout(通道1)和Stderr(通道2)。
  • :Output部分只需获取%%A %%B %%C %%D部分发送的:Input值,然后按常规方式处理它们;输入数据通过findstr命令从Stdin读取。
  • :Input:Output部分可以位于单独的批处理文件中,但它们包含在同一文件中,并通过参数和if "%1" neq "" goto %1命令放置在开头。
  • 最有趣的代码是并行运行3个进程的管道。 :输入部分运行及其Stdout输出进入第一个:输出过程。 Stderr输出(通道2):输入部分通过2>&1重定向到Stdin,因此该输出被输入到第二个:输出过程。

此方法也可用于两个以上的输出并行进程;你只需要添加更多类似的部分,将数字2更改为3,等等。例如,有三个输出流程,管道应该是这个:

( ( "%~F0" Input  |  "%~F0" Output ) 2>&1  |  "%~F0" Output ) 3>&1  |  "%~F0" Output

然而,非常重要您注意到此方法 NOT 必然意味着整个过程运行得更快!这一点取决于几个因素,例如CPU核心数和磁盘驱动器的速度/缓冲区。只是一个测试可以回答这个问题......

请发布结果。