Комментарии 19
Спасибо за статью, интересно. Но всё же, как надоел это пример про генераторы и корутины с чтением файла по строкам!
"Конечно, нужно отметить, что мы получаем возможность работы с
потенциально бесконечными задачами, что без генераторов невозможно."
Но почему-то всегда приводится этот пример, который элементарно переписывается без всяких генераторов. При этом, также останется чтение по строкам, без считывания всего файла в память. И в обычной работе, в коде вроде порой хочется ввернуть генератор. Даже напишешь, а потом понимаешь что можно проще и понятнее без него.
Может есть какой-то пример, где действительно без них никак, и есть настоящая польза?
Может есть какой-то пример, где действительно без них никак, и есть настоящая польза?
Конечно есть. Представьте себе файл со списком недействительных паспортов: https://проверки.гувм.мвд.рф/upload/expired-passports/list_of_expired_passports.csv.bz2
Всего-то 500+ мегабайт CSV в архиве. Сделайте его обработку без генераторов и со считыванием всего файла в память.
но зачем загружать файл в память целиком? Если вы его можете обрабатывать построчно с генератором, читайте так же построчно без генератора. обработали строку, выдали результат - взяли следующую.
И если вам для работы с файлом, по условию задачи, необходимо считать его весь в память (ну мало ли, что там за формат внутри) , то генератор вам уже не поможет, все равно придется считать.
Вы "ищете блох" в конкретном примере, утверждая, что ложку можно вырезать из полена и без рейсфедера.
Я же вам рассказываю - что такое рейсфедер и как его применять, безотносительно ложки.
Причем тут ваш пример?
Причем тут ваш пример?
Это не мой пример, это ваш (и не только) пример. Он хорошо показывает "как работают генераторы" и плохо показывает "как получить пользу от применения генераторов".
Я всего лишь спросил, надеясь на ваш богатый опыт, нет ли другого примера, где использование генератора приводит к реальной экономии ресурсов, которой не достичь без оного. Ну нет, так нет.
Попробую ответить самому себе, какое у меня к данному моменту сложилось впечатление (но может, у кого-то еще найдется пример):
- Чтобы реализовать аналогичный функционал без генератора, вам придется или использовать свой объект с состоянием, или вынести весь код в тело цикла, где и будет состояние выполнения тех или иных операций. В первом случае все довольно просто, но дополнительная писанина и размножение сущностей. Во втором случае - может получиться сложночитаемая каша. Таким образом главная выгода от генераторов - сокращение и упрощение кода, но вовсе не экономия ресурсов. И выгода тем больше, чем больше этаких "задач с состоянием" мы пытаемся выполнить за такт цикла, и чем больше кода в каждой "задаче".
https://www.php.net/manual/ru/function.fgets.php
Внезапно, здесь пример чтения файла без генераторов (размер файла значения не имеет, потому что чтение будет происходить построчно).
Присоединяюсь к вопросу: есть пример использования генераторов не про чтение файлов?
Отличная статья! PHP - сила!
Возможно ли такое в PHP с использованием стандартного синтаксиса языка и стандартной библиотеки?
Нет.
Ну как сказать, вот набросал на коленке по-быстрому: https://github.com/SerafimArts/simple-interval-example
P.S. А, дочитал до момента где описывается React c почти аналогичной реализацией. Зря получается пример набрасывал: "Коммент пиши — статью не читай", ага.
Тогда я не понял почему в этом тезисе "нет" написано? Что стандартными средствами языка подобное невозможно.
Кирилл, я имел в виду, что в стандартной библиотеке нет готового "setInterval" или иных инструментов, чтобы отложить задачу.
А за пример спасибо, интересно.
Кирилл, я имел в виду, что в стандартной библиотеке нет готового "setInterval" или иных инструментов, чтобы отложить задачу.
Давай я чуток подушню тогда)))
Чтобы именно "отложить" задачу — могу назвать как минимум 3 сходу:
$deferred = new class {
public function __destruct() {
echo 'Deferred';
}
};
echo 'Some ';
// Some Deferred
<?php
declare(ticks=1);
register_tick_function(function () {
echo 'ТАЙМЕР';
});
echo 'делаем';
echo 'какую-то';
echo 'фигню';
// ТАЙМЕРделаемТАЙМЕРкакую-тоТАЙМЕРфигнюТАЙМЕР
<?php
register_shutdown_function(function () {
echo 'Я всё';
});
echo 'Привет';
echo 'Мир';
// ПриветМирЯ всё
Ты не душнишь, ты экзотику накидываешь, за что тебе большое спасибо! ))
Всё же хочется откладывать до наступления кастомного события, а не в прибитый гвоздями к жизненному циклу хендлер. Вот тики, кстати, можно заиспользовать совместно с глобальными переменными, но это будет "лекарство хуже болезни" :)
Hidden text
<?php
declare(ticks=1);
$ticks = 0;
$break = null;
register_tick_function(
function () {
global $ticks, $break;
$ticks++;
if ($break != null && $ticks > $break) {
die("DIE MOTHERFUCKER, DIE!!!");
}
}
);
while (true) {
sleep(1);
echo "I'm alive for tick $ticks" . PHP_EOL;
if (rand(0, 100) > 50) {
echo "Death looking for you" . PHP_EOL;
$break = $ticks + 2;
}
}
https://www.php.net/manual/ru/intro.pcntl.php только для cgi/cli. что сильно ограничивает применение. https://stackoverflow.com/questions/35026153/call-to-undefined-function-pcntl-fork-php-fpm-nginx#answer-35029409 комментарий от Joe Watkins.
parallel
погиб - комментарий от тогоже Joe Watkins https://github.com/krakjoe/parallel/issues/201#issuecomment-892442141
по факту нужно смотреть в сторону swoole/amphp
Fiber появились ранее версии php 8.1, они в виде ext были
Интересная статья, спасибо.
Думая о параллельности, хотел спросить. А если я из php кода инициализирую другой http запрос на свой же скрипт, например с другими get-параметрами, и не буду ждать ответа, то получается сервер сам создаст новый процесс в параллель и будет одновременное выполнение?, и таким образом тоже можно запустить задачи в несколько потоков?
или нет возможности отправить запрос и не ждать ответа?
Можно, но так не делают обычно из-за накладных расходов.
Создать неблокирующий http запрос на endpoint некого ресурса встроенными средствами PHP можно
Через библиотеку curl, а именно можно смотреть в сторону функции curl_multi_init()
Либо общением через сокет и установку неблокирующего режима, см. функцию socket_set_nonblock
Но на практике это означает проблемы:
Обычно нужно убедится, что endpoint принял запрос, поэтому код придется формировать, либо в асинхронной манере, либо "лапшично" некрасивым образом.
Такой подход - это полный цикл: нахождение хоста, стук к веб-серверу, поднятие процесса PHP (если мы говорим про endpoint тоже на PHP) и т.п. В общем это не выгодно по ресурсам и гораздо дольше нежели форкнуть процесс, создать поток или запихнуть задачу в очередь и выполнить асинхронно.
Асинхронность, конкурентность, параллельность, многопоточность — разбираемся «по понятиям» :)