Индикатор выполнения

При выполненнии более длительных команд, может быть полезно отображать информацию о выполнении, которая обновляется во время исполнения команды:

../../../_images/progressbar.gif

Чтобы отобразить детали выполнения, используйте ProgressBar, передайте ему общее количество единиц и продвиньте выполнение во время команды:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
use Symfony\Component\Console\Helper\ProgressBar;

// создаёт новый индикатор выполнения (50 единиц)
$progressBar = new ProgressBar($output, 50);

// запускает и отображает индикатор выполнения
$progressBar->start();

$i = 0;
while ($i++ < 50) {
    // ... сделать какую-то работу

    // продвигает индикатор выполнения на 1 едииицу
    $progressBar->advance();

    // вы также можете продвинуть индикатор выполнения больше, чем на 1 единицу
    // $progressBar->advance(3);
}

// гарантирует, что индикатор выполнения достиг 100%
$progressBar->finish();

Tip

Вы также можете продвинуться по индикатору в другом направлении (т.е. сделать шаг назад), вызвав $progress->advance() с отрицательным значением. Например, если вы вызовете $progress->advance(-2), то это уменьшит выполнение на 2 шага.

Вместо продвижения индикатора на количество шагов (с методом advance()), вы также можете установить текущий прогресс, вызвав метод setProgress().

Tip

Если ваша платформа не поддерживает коды ANSI, обновления в индикаторе выполнения добавляются в виде новых строчек. Чтобы предотвратить перенасыщения вывода, соответствующе настройте setRedrawFrequency(). По умолчанию, при использовании max, частота обновления установлена, как 10% вашего max.

Если вы не знаете точное количество шагов в продвижении, установите резонное значение, а потом вызовите метод setMaxSteps(), чтобы обновить его так, как надо:

1
2
3
4
5
// начните с индикатора выполнения на 50 единиц
$progressBar = new ProgressBar($output, 50);

// только что было создано сложное задание; увеличьте индикатор выполнения до 200 единиц
$progressBar->setMaxSteps(200);

New in version 4.1: Метод setMaxSteps() был представлен в Symfony 4.1.

Другим решением будет просто опусить аргумент шагов при создании экземпляра ProgressBar:

1
$progressBar = new ProgressBar($output);

Тогда прогресс будет отображён в виде троббера:

1
2
3
4
5
6
7
8
9
# нет максимального количества шагов (отображает его, как троббер)
    0 [>---------------------------]
    5 [----->----------------------]
    5 [============================]

# максимальное количество шагов определено
 0/3 [>---------------------------]   0%
 1/3 [=========>------------------]  33%
 3/3 [============================] 100%

Каждый раз по завершению задачи, не забудьте вызвать finish(), чтобы гарантировать, что индикатор выполнения обновлён до 100% аавершения.

Note

Если вы хотите вывести что-то во время работы индикатора выполнения, вначале вызовите clear(). После того, как вы закончите, вызовите display(), чтобы отобразить индикатор выполнения снова.

Настройка индикатора выполнения

Встроенные форматы

По умолчанию, инфрмация, отображённая в индикаторе выполнения, зависит от текущего уровня детализации экземпляра OutputInterface:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# OutputInterface::VERBOSITY_NORMAL (CLI без флажка детализации)
 0/3 [>---------------------------]   0%
 1/3 [=========>------------------]  33%
 3/3 [============================] 100%

# OutputInterface::VERBOSITY_VERBOSE (-v)
 0/3 [>---------------------------]   0%  1 сек
 1/3 [=========>------------------]  33%  1 сек
 3/3 [============================] 100%  1 сек

# OutputInterface::VERBOSITY_VERY_VERBOSE (-vv)
 0/3 [>---------------------------]   0%  1 сек
 1/3 [=========>------------------]  33%  1 сек
 3/3 [============================] 100%  1 сек

# OutputInterface::VERBOSITY_DEBUG (-vvv)
 0/3 [>---------------------------]   0%  1 сек/1 сек  1.0 MB
 1/3 [=========>------------------]  33%  1 сек/1 сек  1.0 MB
 3/3 [============================] 100%  1 сек/1 сек  1.0 MB

Note

Если вы вызовtnt команду с флажком заглушения (-q), то индикатор выполнения не будет отображён.

Вместо того, чтобы полагаться на режим детализации текущей команды, вы также можете форсировать формат через setFormat():

1
$progressBar->setFormat('verbose');

Следующие форматы являются встроенными:

  • normal
  • verbose
  • very_verbose
  • debug

Если вы не установите количество шагов для вашего индикатора выполнения, используйте варианты _nomax:

  • normal_nomax
  • verbose_nomax
  • very_verbose_nomax
  • debug_nomax

Пользовательские форматы

Вместо использования встроенных форматов, вы также можете установить собственные:

1
$progressBar->setFormat('%bar%');

Это устанавливает формат, чтобы отображать только сам индикатор:

1
2
3
>---------------------------
=========>------------------
============================

Формат индикатора выполнения - это строка, содержащая заполнители (имя, заканчивающееся символом %); заполнители заменяются в зависимости от текущего прогресса индикатора. Вот список встроенных заполнителей:

  • current: Текущий шаг;
  • max: Максимальное количество шагов (или 0, если максимум не определён);
  • bar: Сам индикатор;
  • percent: Процент выполнения (не доступен, если не определён максимум);
  • elapsed: Время, прошедшее с начала запуска индикатора выполнения;
  • remaining: Оставшееся время для выполнения задачи (не доступно, если не определён максимум);
  • estimated: Предполагаемое время для выполнения задачи (не доступно, если не определён максимум);
  • memory: Текущее исползование памяти;
  • message: используется для отображения произвольных сообщений в индикаторе (объсняется ниже).

Например, вот как вы можете установить такой же формат, как и debug:

1
$progressBar->setFormat(' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%');

Заметили часть :6s, добавленную к некоторым заполнителям? Это то, как вы можете настроить внешний вид индикатора (форматирование и расположение). Часть после двоеточия (:) используется для установки формата строки sprintf.

Вместо установки формата для заданного экземпляра индикатора выполнения, вы можете также определить глобальные форматы:

1
2
3
4
ProgressBar::setFormatDefinition('minimal', 'Progress: %percent%%');

$progressBar = new ProgressBar($output, 3);
$progressBar->setFormat('minimal');

Этот код определяет новый формат minimal, который вы потом можете использовать для ваших индикаторов выполнения:

1
2
3
Progress: 0%
Progress: 33%
Progress: 100%

Tip

Почти всегда лучше переопределить встроенные форматы, чем создавать новые, так как это позволяет отображение разниваться автоматически, основываясь на флажке детализации команды.

При определении нового стиля, содержащего заполнители, которые доступны только при заданном максимальном количестве шагов, вы должны создать вариант _nomax:

1
2
3
4
5
ProgressBar::setFormatDefinition('minimal', '%percent%% %remaining%');
ProgressBar::setFormatDefinition('minimal_nomax', '%percent%%');

$progressBar = new ProgressBar($output);
$progressBar->setFormat('minimal');

При отображении индикатора выполнения, формат будет автоматически установлен, как minimal_nomax, если шкала не имеет максимального количества шагов, как в примере выше.

Tip

Формат может содержать любые валидные коды ANSI, а также использовfm специфический способ Symfony для установки цветов:

1
2
3
4
ProgressBar::setFormatDefinition(
    'minimal',
    '<info>%percent%</info>\033[32m%\033[0m <fg=white;bg=blue>%remaining%</>'
);

Note

Формат может занимать больше одной строчки; это очень полезно, когда вы хотите отобразить больше контекстной нформации рядом с индикатором выполнения (см. пример в начале этой статьи).

Настройки индиактора

Среди заполнителей, bar немного выделяется, так как все символы, используемые для его отображения, могут быть настроены:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// законченная часть индикатора
$progressBar->setBarCharacter('<comment>=</comment>');

// незаконченная часть индикатора
$progressBar->setEmptyBarCharacter(' ');

// символ прогресса
$progressBar->setProgressCharacter('|');

// ширина индикатора
$progressBar->setBarWidth(50);

Caution

По причинам производительности, будьте осторожны, если вы устанавливаете большое общее количество шагов. Например, если вы итерируете большое количество объектов, рассмотрите установку более высокого значения частоты обновления, вызвав setRedrawFrequency(), чтобы он обновился только в некоторых итерациях:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$progressBar = new ProgressBar($output, 50000);
$progressBar->start();

// обновлять каждые 100 итераций
$progressBar->setRedrawFrequency(100);

$i = 0;
while ($i++ < 50000) {
    // ... сделать какую-то работу

    $progressBar->advance();
}

Пользовательские заполнители

Если вы хотите отобразить некоторую информацию, зависящую от отображения индикатора выполнения, недоступную в списке встроенных заполнителей, вы можете создать собственный. Давайте посмотрим, как вы можете создать заполнитель remaining_steps, отображающий количество оставшихся шагов:

1
2
3
4
5
6
ProgressBar::setPlaceholderFormatterDefinition(
    'remaining_steps',
    function (ProgressBar $progressBar, OutputInterface $output) {
        return $progressBar->getMaxSteps() - $progressBar->getProgress();
    }
);

Пользовательские сообщения

Индикаторы выполнения определяют заполнитель под названием message для отображения произвольных сообщений. Однако, ни один из встроенных фрматов не включает в себя этот заполнитель, поэтому до отображения этих сообщений вы должны определить ваш собственный пользовательский формат:

1
2
3
4
ProgressBar::setFormatDefinition('custom', ' %current%/%max% -- %message%');

$progressBar = new ProgressBar($output, 100);
$progressBar->setFormat('custom');

Теперь, используйте метод setMessage(), чтобы установить значение заполнителя %message% до отображения индикатора выполнения:

1
2
3
4
5
6
7
8
// ...
$progressBar->setMessage('Start');
$progressBar->start();
// 0/100 -- Start

$progressBar->advance();
$progressBar->setMessage('Задача в процессе выполнения...');
// 1/100 -- Задача в процессе выполнения...

Сообщения могут также быть объединены с пользовательскими заполнителями. В этом примере, индикатор выполнения использует заполнители %message% и``%filename%``:

1
2
3
4
ProgressBar::setFormatDefinition('custom', ' %current%/%max% -- %message% (%filename%)');

$progressBar = new ProgressBar($output, 100);
$progressBar->setFormat('custom');

Метод setMessage() принимает второй необязательный аргумент для установки значения пользовательского заполнителя:

1
2
3
4
5
6
7
8
// ...
// $files = array('client-001/invoices.xml', '...');
foreach ($files as $filename) {
    $progressBar->setMessage('Импорт счетов...');
    $progressBar->setMessage($filename, 'filename');
    $progressBar->advance();
    // 2/100 -- Импорт счетов... (client-001/invoices.xml)
}

Отображение нескольких индикаторов выполнения

New in version 4.1: Функция отображения нескольких индикаторов выполнения, используя разделы вывода, была представлена в Symfony 4.1.

При использовании Разделов вывода консоли, возможно отображать несклько индикаторов выполнения одновременно и изменять их прогресс независимо друг от друга:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
$section1 = $output->section();
$section2 = $output->section();

$progress1 = new ProgressBar($section1);
$progress2 = new ProgressBar($section2);

$progress1->start(100);
$progress2->start(100);

$i = 0;
while (++$i < 100) {
    $progress1->advance();

    if ($i % 2 === 0) {
        $progress2->advance(4);
    }

    usleep(50000);
}

После нескольких итераций вывод в терминале будет выглядеть так:

1
2
34/100 [=========>------------------]  34%
68/100 [===================>--------]  68%

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.