Комментарии 40
Реактивное программирование — парадигма программирования, ориентированная на потоки данных и распространение изменений.
где здесь потоки данных и распространение изменений?
Статья демонстрирует возможности метода ratelimit, такой метод можно и в какой-нибудь lodash запихать, работать будет ничуть не хуже.
Набросал:
<script>
function LimitQueue(limit, timeout) {
this.limit = limit;
this.timeout = timeout;
this.jobs = [];
this.pending = 0;
this.results = [];
this._run = this._run.bind(this);
}
LimitQueue.prototype.push = function(jobs) {
Array.prototype.push.apply(this.jobs, jobs);
};
LimitQueue.prototype._run = function(results) {
if (results) {
this.pending = 0;
Array.prototype.push.apply(this.results, results);
setTimeout(this._run, this.timeout);
if (!this.jobs.length) {
this.callback(this.results);
}
return;
}
let promises = [];
for (;;) {
if (this.pending == this.limit || !this.jobs.length) {
Promise.all(promises).then(this._run);
break;
}
promises.push(this.jobs.shift()());
this.pending++;
}
};
LimitQueue.prototype.onDone = function(cb) {
this.callback = cb;
this._run();
};
// ========
let q = new LimitQueue(3, 1000);
q.push(
[{ name: 'Max1' }, { name: 'Max2' }, { name: 'Max3' }, { name: 'Max4' }, { name: 'Max5' }].map(
data => () => {
console.log(1, data.name);
return new Promise((resolve, reject) => {
console.log(2, data.name);
setTimeout(() => {
console.log(3, data.name);
resolve(data.name);
}, Math.ceil(Math.random() * 3000));
});
}
)
);
q.onDone(results => {
console.log(4, results);
});
</script>
В консоли следующее:
1 "Max1"
2 "Max1"
1 "Max2"
2 "Max2"
1 "Max3"
2 "Max3"
[задержка]
3 "Max3"
[задержка]
3 "Max1"
[задержка]
3 "Max2"
[задержка 1000ms]
1 "Max4"
2 "Max4"
1 "Max5"
2 "Max5"
[задержка]
3 "Max5"
[задержка]
3 "Max4"
4 (5) ["Max1", "Max2", "Max3", "Max4", "Max5"]
Завернуть всё это в красивый интерфейс уже не проблема и как видите нет никаких потоков.
UPD: накосячил конечно немного, но суть я думаю понятна.
4 [ 201, 201, 201, 201, 201 ]
4 [ 201, 201, 201, 201, 201 ]
4 [ 201, 201, 201, 201, 201 ]
4 [ 201, 201, 201, 201, 201 ]
4 [ 201, 201, 201, 201, 201 ]
да)), про это я и написал:
UPD: накосячил конечно немного, но суть я думаю понятна.
Поотлаживать конечно не помешает, считайте, что это псевдокод демонстрирующий как это делать без потоков.
1 вызов займет 1с
2 вызов займет 5с
3 вызов займет 1с
через сколько времени начнется:
4-й вызов?
5-й вызов?
вот сервер с реальным тротлингом, там же код batchCreate и логи для сервера и create
Вот как выглядит кусочек лога(это нет тоже лог что в гисте!)
app finished 3 +53ms
app finished 2 +572ms
app finished 1 +11ms
app finished 0 +1s
app start 5 +1ms
app start 6 +1ms
app start 7 +0ms
app start 8 +0ms
app finished 4 +76ms
app start 9 +0ms < — свободное окно и пошел вызов, не дожидаясь окончания всех долгоиграющих запросов
app finished 6 +188ms
app finished 8 +1s
app finished 5 +74ms
app finished 9 +244ms
app finished 7 +121ms
понимайте о чем я? сможете так доизменить свой код? прошу заметить в коде batchCreate измененно две строчки(имею ввиду по сути, а не добавлен логгинг)
понимайте о чем я?
понимаю, так ещё оптимальнее, но не вижу проблемы написать и это без потоков, навскидку, мне кажется, даже кода меньше получится (чем сейчас в примере выше). Только давайте по очереди? Мне просто не особо интересно такие задачки решать. Попробуйте сами, а я уже попробую сделать ещё проще.
но не вижу проблемы написать и это без потоков, навскидку, мне кажется, даже кода меньше получится
Я как раз тут проблему вижу. По-этому, если вам нечего больше сказать – давайте не будем занимать время друг-друга. Спасибо
всё правильно, это мои слова, для меня это действительно не сложная задача, но я же не говорил, что хочу потратить ещё пол часа своего времени.
Я как раз тут проблему вижу
в чём проблема, в задаче? Вы действительно считаете её нерешаемой без потоков, серьёзно? Что там в потоках по вашему, божественный эфир? Или проблема в вас? Тогда это тем более в ваших интересах, потренируетесь. А то на собеседованиях уже страшно просить что-то простейшее написать.
Завернуть всё это в красивый интерфейс – давайте исходить из того что в красивый интерефейс можно что угодно завернуть
Вы согласны с тем что эта задача не настолько тривиальна, как кажется на первый взгляд?
честно, нет, для меня сложность сразу ясна.
давайте исходить из того что в красивый интерефейс можно что угодно завернуть
вы же не хотите сказать, что внутри highland что-то более простое чем я предложил?
вы предлагаете написать штуку которая решает одну задачу
почему нет?
Хотя вопрос риторический, мне не нужно объяснять зачем объединять что-то в библиотеки, речь не про это, я говорю, что приведённый вами пример в статье никак не показывает плюсов реактивного программирования, а его ключевая часть легко переносится в другие библиотеки никак не связанные с РП. Если бы мне так объясняли РП я бы сказал "круто", но никогда бы не стал его использовать для себя.
в вашем коде навскидку 70 cтрок
в моем 10
это если еще опустить факт того что там есть пассажи вида:
for (;;) {
if (this.pending == this.limit || !this.jobs.length) {
которые нужно вдумчиво читать
С Аргументом «вы же не хотите сказать, что внутри highland что-то более простое чем я предложил?» я не знаю как спорить – ним можно отбросить любую парадигму программирования и заменить ее на на набор функций
в вашем коде навскидку 70 cтрок
в моем 10
причём тут количество строк? Ок, представьте другую библиотеку внутри которой ratelimit на основе моего кода. Представьте в lodash завтра появляется ratelimit реализованный без потоков. Как теперь докажете необходимость РП?
буду рад если вы укажите ссылки на лучшие примеры
я делал несколько докладов про РП и как-то начинал писать статью на эту тему. И каждый раз основной проблемой был именно хороший пример, глядя на который сразу становилось бы ясно, что это и зачем. Фишка РП в том, что плюсы становятся особенно видны именно в сложных ситуациях, а такое в статью или доклад не запихаешь. Мне нечего вам предложить в виде одного примера, но я похоже в скором времени ещё раз попробую написать такую статью. Может со второй попытки что-то получится.
исходя из вашей логики, можно отменить «все» аргументируя тем, что это можно на машином коде написать.
Эта ветка ушла в холивар – это не интересно. предлагаю закончить. продолжить там где код
Мне кажется в статье было куда больше смысла, если бы:
.ratelimit(5, 1000)
был написан "руками" с пояснениями. Тогда это была бы демонстрация "на пальцах", как можно удобно работать со stream-ми асинхронных данных. Вместо этого мы видим статью, которая сводится к "в highland для этого есть готовый удобный метод". Зачем? :)
И мне кажется в статье под названием "Самое краткое введение в Reactive Programming" должно быть простейшее описание паттерна Observer. А не реактивные библиотечные потоки с тыщей мутных методов :)
мне так не кажется. Проще думать об этом как именно о потоках – отсюда «качаю», сюда «заливаю». Потом человек уже сам почитает про все остальное. Оставить статью краткой и рассказать о всем – заведомо не достижимая цель.
Ну вот смотрите. Приходит человек читать про реактивное программирование. Он не знает что такое stream-ы и протокола их работы. Он не знает где эти странные штуки могут быть удобными. Он не знает паттерна наблюдатель. Он весь во внимании. Ведь это краткое введение, ему сейчас всё объяснят. Что в итоге он видит в этой статье? Хм… Ну что есть какие-то сторонние библиотеки, которые позволяют записать привычные вещи в странном виде. Он хочет пояснений — а зачем так? Что тут под капотом происходит? А вы ему пример с rateLimit. Он думает — вот, интересный пример, сейчас мне всё расскажут и покажут. Вы говорите ему, мол есть готовый метод в 1 строку. Почувствуй силу rxjshighland, о юный падаван! Он в ответ — эээээ, что? На этом статья заканчивается. Что нового для себя подчерпнул человек? В чём был "message"? :) Смотрите, как я могу?
Даже зная как работают nodejs-streams, observer-ы и пр. штуки, может быть совершенно не очевидно, в каких реальных жизненных обстоятельствах, эти непривычные подходы могут оказаться к месту. Тут ведь как с каррированием. Раз в неделю кто-нибудь пишет статью про то, что это такое. Однако людей, которые нашли ему применение в своих реальных задачах можно пересчитать по пальцам одной руки (ладно, тут я несколько утрирую).
Самое краткое введение в Reactive Programming