@oenomaus2013

Как правильно сделать прогресс выполнения фоновой задачи?

интересует больше бэкенд сторона
например:
1) конвертация видео в другой формат
2) сжатие большого изображения
3) импорт товаров в бд с внешнего api
4) экспорт товаров из бд в excel файл

предполагаю алгоритм зависит от вида задачи..

случай 3: если это импорт..то нужно вероятно подсчитать количество строк/рядов в файле,например там около 300 строк,
в бд добавляем по 100 строк
количество итераций = 300/100=3
всего 3 итерации: 1-33%, 2-66%, 3-100%

случай 2 "сжатие большого изображения"..
как узнать здесь количество итераций?
или в момент запуска воркера,увеличивать счетчик прогресса каждую секунду и
записывать/обнволять в бд по id_task значение в поле "progress" , а когда закончит работу обновить значение на 100%

общий алгоритм возможно должен быть похож на это:
function progress(int $total)
{
    echo 'Starting task' . PHP_EOL;
    for ($i = 1; $i <= $total; $i++) {
        $progress = 100 * $i / $total;
        echo $i . '-' . $progress . '%' . PHP_EOL;
        // some heavy task
        sleep(1);
    }
    $progress = 100;
    echo '$progress: ' . $progress . '%' . PHP_EOL;
    echo 'Task completed' . PHP_EOL;
}

progress(10);
  • Вопрос задан
  • 76 просмотров
Пригласить эксперта
Ответы на вопрос 1
gzhegow
@gzhegow
aka "ОбнимиБизнесмена"
В пхп асинхронной работы в коробке нету (но сделать её - можно). Это значит, что либо вы делаете два скрипта, причем один пишет "в файл" (а лучше другое быстрое хранилище) твой процент, а второй в нужный момент этот файл считывает и показывает тебе процент в текущий момент.

Для понимания хорошо помогает ролик про javascript event-loop. Идея там в том, что любая задача делится на шаги, и в конце запускается бесконечный цикл, висящий на списке запланированного. Пока список не пустой, выполняется 1 шаг для каждой цепочки (то есть step1-step1-step1) и куда-то пишется прогресс. Потом цикл повторяется, выполняется второй шаг (step2-step2-step2). Важно здесь не ошибится и не сделать ненароком асинхронку, которая делает (step1-step2-step3, step1-step2-step3) это нарушит параллельность. Дальше разработчик решает - шаг это одна запись, или например 10 тыщ.

Вот в том месте где вы пишете:
echo $i . '-' . $progress . '%' . PHP_EOL;
должна быть запись в какое-то место, в кеш или в редис.

А другим скриптом вы это место потом выводите по первому требованию.

Есть более сложная реализация, когда открывается сокет и все равно два скрипта - один делает задачу, второй подключается. Первый периодически пишет в сокет что-то вроде "progress:90", а второй, подключившись, получает сообщение и видит, что начинается со слова progress и выводит уже такое.

Часто эту задачу решают, когда работают например с пережиманием одного большого файла. В этом случае нужно брать размер выходного файла, который в данный момент делается и делить размер на предполагаемый конечный размер. Этим кстати объясняются старые приколы windows, когда она писала 99% а потом долго долго висела, т.к. спрогнозировать сколько будет весить выходной файл бывает сложно.

Что до конкретно вашего случая - не до конца понимаю зачем в таком цикле делать опросник прогресса выполнения. Вы решаете консольную задачу, выводите в консоли $total - $i, и будете видеть сколько осталось. Разве что у вас есть необходимость ещё кому-то это показать - то да, как написал выше.

Заказчику редко нужно видеть полоску с процентом, её делать дороговато для него. Как правило достаточно статус менять на "выполняется" и пусть вам пишет если это "выполняется" уже неделю как висит.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы