此问题用于在Windows 2012服务器上运行perl。
所以我有一个名为Commands_To_Run的文件夹,在该文件夹下有100个批处理文件,例如
Commands_To_Run
- run_1.bat
- run_2.bat
- run_3.bat
...
- run_100.bat
每个这些run * .bat文件大约需要30分钟才能完成。如果我使用FOR循环顺序运行这些批处理文件,则需要100 * 30分钟才能运行。 (太长了!)
我要写的是一个Perl脚本,它将一次执行10个批处理文件。一旦任何一个批处理文件完成,下一个批处理文件将被执行。
例如,我想通过run10.bat执行run1.bat。假设run7.bat完成,然后我要运行下一个run11.bat,依此类推。因此,在任何给定时间运行10个文件。
我考虑过使用此perl脚本来运行批处理文件,但这将同时运行所有100个文件,这将杀死我的Windows CPU和处理程序。
for ($x=0; $x < scalar(@files); $x++ ) {
$file=@files[$x];
chomp $file;
$cmd="start $file ";
print "Runnung Command is: $cmd\n";
system($cmd);
}
我查看了给出的建议,但是没有使用Forks :: Super的有效示例
答案 0 :(得分:3)
fmap_scalar function from Future::Utils可以处理保持一定数量的进程运行的所有逻辑,而IO::Async::Process可以异步运行和管理每个进程(如果是Windows,我不确定是否所有这将明智地工作):
use strict;
use warnings;
use IO::Async::Loop;
use Future::Utils 'fmap_scalar';
my @commands = ...;
my $loop = IO::Async::Loop->new;
my $f = fmap_scalar {
my $cmd = shift;
my $f = $loop->new_future;
$loop->open_process(command => $cmd, on_finish => sub { $f->done($_[1]) });
return $f;
} foreach => \@commands, concurrent => 10;
my @exit_codes = $f->get; # starts the loop until all processes are done
答案 1 :(得分:3)
use warnings;
use strict;
use feature 'say';
use Parallel::ForkManager;
my $pm = Parallel::ForkManager->new(10);
# Prepare the list of your batch files (better get names from disk)
my @batch_files = map { "Commands_To_Run/run_$_.bat" } 1..100;
foreach my $batch_file (@batch_files)
{
$pm->start and next;
# Run batch job
say "Running: $batch_file";
#system($batch_file); # uncomment to actually run the jobs
$pm->finish;
}
$pm->wait_all_children;
这是一个最小但有效的脚本。例如,请参见this post和this post,详细了解作业的进行方式,尤其是如何从作业中返回数据。
注意:这不是核心模块,因此您可能需要安装
答案 2 :(得分:1)
Parallel :: ForkManager依赖于fork
,这是Unix系统的一项功能,在Windows系统上,Perl(使用线程)对该功能进行了严重严重模仿。我建议直接使用线程代替。更少的东西可能会出错。
use threads;
use Thread::Queue 3.01 qw( );
sub worker {
my ($command) = @_;
system($command);
}
{
my $q = Thread::Queue->new();
for (1..10) {
async {
while (my $job = $q->dequeue()) {
worker($job);
}
}
}
$q->enqueue($_) for @commands;
$q->end();
$_->join for threads->list;
}
答案 3 :(得分:0)
只需将其放到那里,但是也可以使用批处理文件来执行此操作,这应该遍历所有.bat
文件,检查进程计数,并且如果进程不少于或仅检查新文件,等于9(如果等于9,则仍会踢出1):
@echo off
setlocal enabledelayedexpansion
set cnt=1
for %%i in (*.bat) do (
set id=%%i
call :check
)
:check
for /f "tokens=1,*" %%a in ('tasklist /FI "WINDOWTITLE eq _process*" ^| find /I /C "cmd.exe"') do set procs=%%a
if !procs! leq 9 (
if not "!id!"=="%0" start "_process!cnt!" !id!
set /a cnt+=1
) else (
goto check
)