Coroutines в PHP и работа с неблокирующими функциями
В этой статье я покажу как реализовать планировщик задач с использованием корутин, чтобы вы поняли, что с ними можно делать и как их применять. Начнем с нескольких вступительных слов. Если вы считаете, что вы уже достаточно хорошо знаете как работают генераторы и корутины, тогда можете сразу перейти к разделу «Совместная многозадачность».
Генераторы
Суть генератора в том, что это функция, которая возвращает не просто одно значение, а последовательность значений, где каждое значение выброшено одно за другим. Или, другими словами, генераторы позволяют вам реализовать итератор, без лишнего кода.
Генераторы в действии
Небольшое вступление
Не так давно я решил для себя, что пора восполнить большой пробел в знаниях и решил прочитать про переходы между версиями PHP, т.к. понимал, что остался где-то между 5.2 и 5.3 и этот пробел необходимо как-то устранить. До этого я читал про namespaces, traits и т.д, но дальше чтения не уходило. И вот тут я заметил генераторы, почитал документацию, одну из статей на хабре на этот счет и после этого возникла мысль — а как раньше без них жили-то?
Данным переводом хочу помочь хотя бы новичкам, поскольку на php.net документация по генераторам на английском и, на мой взгляд, должным образом не раскрывает всю идею и места применения. Текста много, кода чуть меньше, картинок нет. Потребуются общие знания, например, про итераторы. Очевидный код комментировать не буду, а вот сложные для понимания примеры постараюсь объяснить в силу своих знаний.
UPD1: Изменил расплывчатую формулировку, про которую говорили в комментариях.
UPD2: Добавил решение с принудительным break.
Отказываемся от коллбэков: Генераторы в ECMAScript 6
JavaScript
. Держать в голове порядок исполнения в этом языке немного трудно (это тот случай, который называют «Callback Hell» или «The Pyramid of Doom»), если до этого ты имел дело с синхронным программированием. Моим обычным ответом было «тебе придется как-то с этим обходиться». В конце концов, ожидаем ли мы, что все языки программирования будут выглядеть и ощущаться одинаково? Конечно нет.Все поменял недавний обзор черновика
ECMAScript 6
, в котором описываются генераторы — возможность языка, которая целиком изменит наш способ написания и серверного, и клиентского JavaScript
. С помощью генераторов мы можем превратить вложенные коллбэки в похожий на синхронный код без блокирования нашей единственной event loop
.Например, этот код:
setTimeout(function(){
_get("/something.ajax?greeting", function(err, greeting) {
if (err) { console.log(err); throw err; }
_get("/else.ajax?who&greeting="+greeting, function(err, who) {
if (err) { console.log(err); throw err; }
console.log(greeting+" "+who);
});
});
}, 1000);
может быть написан так:
sync(function* (resume) {
try (e) {
yield setTimeout(resume, 1000);
var greeting = yield _get('/something.ajax?greeting', resume)
var who = yield _get('/else.ajax?who&greeting=' + greeting, resume)
console.log(greeting + ' ' + who)
}
catch (e) {
console.log(e);
throw e;
}
});
Интересно, не правда ли? Централизованная обработка исключений и понятный порядок исполнения.
Имплементация coroutine в NodeJS
SaltStack: Предварительная генерация паролей для использования в сервисах
О чем статья?
Короткая статейка о том, как сгенерировать пароли необходимые для разнообразных сервисов автоматически устанавливаемых с помощью SaltStack.
Асинхронный рекурсивный итератор и борьба с callback в Node.js
Используя примеры из приведенной статьи, мы можем:
1. Легко написать любой итератор, например, итератор по дереву
2. Написать псевдо-синхронный код (борьба с callback)
Но что делать, если нам надо написать рекурсивный итератор по дереву, а получение дочерних узлов требует вызова асинхронной функции с передачей callback?
Простой рекурсивный итератор (без вызова асинхронных функций) мог бы выглядеть довольно просто и кратко:
function* iterTree(treenode) {
var children = getChildren(treenode);
if (children) { // inner node
for (let i=0; i < children.length; i++) {
yield* iterTree(children[i]); // (*) recursion
}
} else { // leaf node
yield treenode;
}
}
Приведенный выше пример прост, поскольку использует синхронный вызов функции getChildren. Если же функция getChildren асинхронная и требует передачи callback (например, это получение данных с диска или по сети) – то все существенно усложняется. Мы уже не можем так просто написать (следуя примерам из приведенной выше статьи)
let children = yield getChildren(treenode, resumecallback);
В этом случае функция iterTree остановится в месте вызова оператора yield и передаст управление вызывающей функции. Но у нас рекурсивная функция – и вызывающая функция тоже передаст управление выше (оператор yield *). В результате пользователь нашего итератора будет получать узлы дерева, перемежаемые неожиданными значениями.
Генераторы в ES6 и асинхронный код по-новому
Koajs 2.0: новое поколение фреймворка нового поколения

Генерация классов из БД с помощью DataGrip

В этой небольшой заметке будет показано, как написать DataGrip расширение для генерации кода (в данном случае POCO (C#) классов) на основе таблиц из почти любой БД (SQL Server, Oracle, DB2, Sybase, MySQL, PostgreSQL, SQLite, Apache Derby, HyperSQL, H2).
Такая разная асинхронность
Здравствуйте, меня зовут Дмитрий Карловский и я… многозадачный человек. В смысле у меня много задач и мало времени, чтобы их все уже, наконец, закончить. Отчасти это и к лучшему — всегда есть чем заняться. С другой стороны — пока ты разрываешься между проектами, мир катится куда-то не туда и некому забраться на броневик и призвать толпу остановиться и немного подумать. А вопрос-то серьёзный — долгое время мир JS был погружён в ад обратных звонков и с ними не только не боролись — их боготворили. Потом он чуть менее чем полностью погряз в обещаниях. Сейчас к ним с разных сторон усиленно вставляют подпорки разной степени кривизны. А света в конце тоннеля всё не видать. Но обо всём по порядку...
Теория многозадачности
Сперва определимся с терминами. В процессе работы, приложение выполняет различные задачи. Например, "скачать файл с удалённого сервера" или "обработать запрос пользователя".
Не редки ситуации, когда для выполнения одной задачи требуется выполнение дополнительных задач — "подзадач". Например, для обработки запроса пользователя, необходимо скачать файл с удалённого сервера.
Запустить подзадачу мы можем синхронно, и тогда текущая задача заблокируется в ожидании завершения подзадачи. А можем запустить асинхронно, и тогда текущая задача продолжит своё выполнение не дожидаясь завершения подзадачи.
Тем не менее, обычно для завершения выполнения задачи, пусть и не сразу, но требуется и завершение выполнения подзадачи с последующей обработкой её результатов. Блокировку одной задачи в ожидании сигналов от другой будем называть "синхронизацией". В общем случае, синхронизация одних и тех же задач может происходить и множество раз, по самой различной логике, но в дальнейшем мы будем рассматривать лишь простейший и самый распространённый вариант — синхронизацию по завершению подзадачи.
Асинхронный код в синхронный встроенными средствами
В данной статье я на практическом примере расскажу о реализации способа, которым я воспользовался для решения моей задачи. Приступим.
Функции высших порядков и монады для PHP`шников
Среди PHP программ преобладает процедурный или в последних версиях частично объектно-ориентированный стиль программирования. Но можно писать и иначе, в связи с чем хочется рассказать о функциональном стиле, благо кое-какие инструменты для этого имеются и в PHP.
Поэтому мы рассмотрим реализацию парсера JSON в виде простейших функций и функций их комбинирующих в более сложные, постепенно дойдя до полноценного парсера JSON формата. Вот пример кода, который мы получим:
$jNumber = _do(function() {
$number = yield literal('-')->orElse( literal('+') )->orElse( just('') );
$number .= yield takeOf('[0-9]')->onlyIf( notEmpty() );
if ( yield literal('.')->orElse( just(false) ) ) {
$number .= '.'. yield takeOf('[0-9]');
}
return +$number;
});
Кроме собственно функционального подхода можно обратить внимание на использование классов для создания DSL-подобного синтаксиса и на использование генераторов для упрощения синтаксиса комбинаторов.
UPDATE само-собой парсинг JSON уже давно решенная задача и конечно готовая и протестированная функция на C будет работать лучше. Статья использует эту задачу как пример для объяснения функционального подхода. Так же не пропагандируется использование именно такого кода в продакшене, каждый может почерпнуть себе какие-то идеи, которые могут упростить код и жизнь.
Полный код находится на github.
Итерируемый объект, итератор и генератор

Функциональное программирование с PHP-генераторами
Генераторы классные. Они облегчают написание итераторов, определяя функции вместо создания целых классов, реализующих Iterator
. Также генераторы помогают создавать ленивые списки (lazy list) и бесконечные потоки. Главное отличие функции-генератора от обычной функции в том, что обычная может возвращать только один раз (после этого её исполнение прекращается), а функция-генератор в ходе исполнения способна выдавать несколько значений. При этом в перерывах между возвратами исполнение генератора ставится на паузу до следующего запуска. Поэтому генераторы могут использоваться для создания списков с лениво генерируемыми значениями, то есть каждый элемент в списке вычисляется только в момент востребованности.
Асинхронное программирование (полный курс)
Асинхронное программирование за последнее время стало не менее развитым направлением, чем классическое параллельное программирование, а в мире JavaScript, как в браузерах, так и в Node.js, понимание его приемов заняло одно из центральных мест в формировании мировоззрения разработчиков. Предлагаю вашему вниманию целостный и наиболее полный курс с объяснением всех широко распространенных методов асинхронного программирования, адаптеров между ними и вспомогательных проемов. Сейчас он состоит из 23 лекций, 3 докладов и 28 репозиториев с множеством примеров кода на github. Всего около 17 часов видео: ссылка на плейлист.
DIY Корутины. Часть 1. Ленивые генераторы
В мире JVM про корутины знают в большей степени благодаря языку Kotlin и Project Loom. Хорошего описания принципа работы котлиновских корутин я не видел, а код библиотеки kotlin-coroutines совершенно не понятен неподготовленному человеку. По моему опыту, большинство людей знает о корутинах только то, что это "облегченные потоки", и что в котлине они работают через умную генерацию байткода. Таким был и я до недавнего времени. И мне пришла в голову идея, что раз корутины могут быть реализованы в байткоде, то почему бы не реализовать их в java. Из этой идеи, впоследствии, появилась небольшая и достаточно простая библиотека, в устройстве которой, я надеюсь, может разобраться практически любой разработчик. Подробности под катом.

Понимание итераторов в Python
Python — особенный язык в плане итераций и их реализации, в этой статье мы подробно разберём устройство итерируемых объектов и пресловутого цикла for
.
Особенности, с которыми вы часто можете столкнуться в повседневной деятельности
1. Использование генератора дважды
>>> numbers = [1,2,3,4,5]
>>> squared_numbers = (number**2 for number in numbers)
>>> list(squared_numbers)
[1, 4, 9, 16, 25]
>>> list(squared_numbers)
[]
Как мы видим в этом примере, использование переменной squared_numbers
дважды, дало ожидаемый результат в первом случае, и, для людей незнакомых с Python в достаточной мере, неожиданный результат во втором.
2. Проверка вхождения элемента в генератор
Возьмём всё те же переменные:
>>> numbers = [1,2,3,4,5]
>>> squared_numbers = (number**2 for number in numbers)
А теперь, дважды проверим, входит ли элемент в последовательность:
>>> 4 in squared_numbers
True
>>> 4 in squared_numbers
False
Как я писал кодогенератор на PHP и что из этого получилось
Причины и проблемы, которые нужно было решить
В этой статье я вам расскажу о том как я писал кодогенератор на php. Расскажу о пути, который он прошел от генерации простых таблиц, до довольно полноценного генератора html и css кода. Приведу примеры его использования и покажу уже сделанные проекты.
В этом семестре на одном из предметов можно было использовать только PHP.
После бесконеного ренейма проекта Проект получил имя MelonPHP. Чтобы люди думали о еде когда произносили его имя? Но у нас тут статья не о генерации бреда, поэтому давайте я вам расскажу о причине его создания.
Написать надо было много, но это не проблема. Основная проблема заключалась в выводе HTML кода через PHP. Я постараюсь объяснить проблему ниже.
Эффектное программирование. Часть 1: итераторы и генераторы
Далее читателю предложена статья, которая, в случае положительного отклика, может перерасти в цикл. В случае успешного написания мной этого цикла, а Читателем его успешного освоения, про следующий код будет понятно не только то, что он делает, но и как устроен под капотом:
while (true) {
const data = yield getNextChunk(); // вызов асинхронной логики
const processed = processData(data);
try {
yield sendProcessedData(processed);
showOkResult();
} catch (err) {
showError();
}
}
Это первая, пилотная часть: Итераторы и Генераторы.
Часть 2