Perl: выполнить 10 системных процессов асинхронно - PullRequest
0 голосов
/ 19 февраля 2019

Этот вопрос предназначен для запуска perl на сервере Windows 2012.

Итак, у меня есть папка Commands_To_Run, и под ней есть 100 командных файлов, например,

Commands_To_Run
 - run_1.bat
 - run_2.bat
 - run_3.bat 
...
 - run_100.bat

Каждый из них запускается *.Файлы летучих мышей занимают около 30 минут.Если я запускаю эти командные файлы последовательно, используя цикл FOR, тогда мне потребуется 100 * 30 минут для запуска.(Слишком долго!)

Я хочу написать Perl-скрипт, который будет выполнять 10 пакетных файлов одновременно.Как только любой из пакетных файлов завершится, будет запущен следующий пакетный файл.

Например, я хотел бы выполнить run1.bat через run10.bat.Допустим, что run7.bat заканчивается, я хочу запустить следующий run11.bat и так далее.Таким образом, в любой момент времени выполняется 10 файлов.

Я думал об использовании этого сценария Perl для запуска пакетного файла, но он будет запускать все 100 одновременно, и это убьет мой процессор и обработку Windows.

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

Ответы [ 4 ]

0 голосов
/ 19 февраля 2019

Просто поместите его туда, но это можно сделать и с помощью командного файла, это должно циклически проходить по всем .bat файлам, проверять количество процессов и выводить только новые, если процессы не меньше или равны9 (если равняется 9, это все равно будет удар один):

@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
 )
0 голосов
/ 19 февраля 2019

Простой способ запустить процессы параллельно и в очереди с помощью Parallel :: ForkManager

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;

Это минимальный, но работающий скрипт.См., Например, этот пост и этот пост для получения дополнительной информации о том, как идут работы, и в частности о том, как возвращать данные из заданий.

Примечание. Это неосновной модуль, поэтому вам, вероятно, потребуется установить его

0 голосов
/ 19 февраля 2019

Parallel :: ForkManager опирается на fork, особенность систем Unix, которая плохо эмулируется Perl (используя потоки) в системах Windows.Я бы рекомендовал использовать темы напрямую.Меньше может пойти не так, как надо.

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;
}
0 голосов
/ 19 февраля 2019

Функция fmap_scalar из Future :: Utils может обрабатывать всю логику поддержания определенного количества запущенных процессов, а IO :: Async :: Process может запускаться и управлятькаждый процесс асинхронно (учитывая его окна, я не уверен, что все это будет работать разумно):

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...