LINUX.ORG.RU

Будет ли рекурсия в этом случае

 


1

2

Не могу понять, будет ли рекурсия, и, как следствие, постоянное нарастание памяти из-за того, что один вызов func ждет пока завершит выполнение вложенный в нее вызов func итд..

var func = function() {
  console.log('Boo!');
  setTimeout(func, 10);
};

setTimeout(func, 10);
★★★★★

Последнее исправление: makoven (всего исправлений: 2)
Ответ на: комментарий от drBatty

Поставил такой код со значением 1 вместо 10 в node.js. Минут 5 крутился - потребление памяти не поднялось

С целью запустить итерацию асинхронной функции при условии что прошлый вызов завершился. Грубо говоря:

func = -> $.getJSON '/get', (data) ->
  process_data data
  func()

makoven ★★★★★
() автор топика

Однозначно - рекурсия.

Но тут рекурсивно не функция-обработчик выполняется, а рекурсивно ставится обработчик на выполнение по таймеру. Причем обработчик (и выделенная память под него) один и тот же для всех таймеров.

k0valenk0_igor ★★★
()

рекурсия
как следствие, постоянное нарастание памяти

тебя обманули. От рекурсии память у тебя не вырастет.

Bad_ptr ★★★★★
()

рекурсии тут нет ибо «сейчас вызывающий» экземляр вне зависимости от факта «придержаного на 10 чего то там » активации( создание(выбор из пула :) и выполнения) экземляра завершится/завершается .

qulinxao ★★☆
()
Ответ на: комментарий от drBatty

будет

Доктор, ты чего??

а с какой целью писать ТАКОЕ?

А с такой, что по всей видимости func выкидывается из диспетча, и приходится его сувать туда заново по срабатыванию таймаута.

arturpub ★★
()
Ответ на: комментарий от qulinxao

Здесь рекурсивно устанавливается отложенное событие таймера. Грубо говоря, рекурсивно нагружается задачами планировщик.

И если не верите, то попробуйте в консоли браузера запустить сей скрипт... вот тогда и утверждайте на счет рекурсии.

k0valenk0_igor ★★★
()
Ответ на: комментарий от k0valenk0_igor

«Аналогия» твоя понятна, но с таким же успехом можно утверждать, что в любой программе с событийным циклом все точки входа из цикла являются рекурсивными и/или косвенно рекурсивными засчет отложенных и/или псевдоасинхронных действий. Что разумеется не так.

arturpub ★★
()
Ответ на: комментарий от arturpub

Воу-воу-воу. Зачем так нервничать )

Товарищи, а во втором примере будет рекурсия? Сейчас переведу на js

makoven ★★★★★
() автор топика
Ответ на: комментарий от k0valenk0_igor

давай различать рекурсивность(рекурентность) описания и рекурсивность реализации(которая как тут уже выше жирно намекали может даже не «енлардж ю» память при хвостовой оптимизации)

здесь даже если установиш 1 квант экземляры независимы над общим контекстом - между экземлярами(уже запущеными) есть историческая последовательность(кто чей потомок) но нет вложенности возвратов(даже при отсутствии оптимизации)

qulinxao ★★☆
()
Ответ на: комментарий от arturpub

Возможно мы просто не сошлись в терминах.

Да, здесь нет классической рекурсии, когда функция вызывает саму себя. Здесь другой вариант: функция создает задачу, которая выполняясь вызовет ее саму.

Я понимаю так, что эта задача будет активирована не потоком скрипта (он уже другими делами занят), а диспетчером задач js-машины, хотя и в контексте активировавшего ее скрипта. И вот тут становится совсем интересно, потому что если (!) поставленные одним и тем же скриптом задачи, - с одинаковым тайм-аутом, - выполняются не параллельно, а последовательно, то это как раз и объяснит отсутствие отжирания памяти, которое наблюдается.

k0valenk0_igor ★★★
()
Ответ на: комментарий от makoven

Вот в таком. Рекурсия в смысле сохранения стека вызовов и последующего его переполнения. Ведь конца этим вызовам не будет..

func = function() {
  return $.getJSON('/get', function(data) {
    process_data(data);
    return func();
  });
};

makoven ★★★★★
() автор топика
Ответ на: комментарий от k0valenk0_igor

Здесь рекурсивно устанавливается

вот эти слова напоминают казуистику «пту(фазанка)»-стайл высших-заборостроительных где обьекты в С++ обмениваются сообщениями ибо (*)в святом ооп обьекты с сообщениями и никак иначе (**) С++ свято ооп СЛЕДОВАТЕЛЬНО .

а уж доказательство через пример - т.е. все птицы летают ибо ворона летает это +много.

qulinxao ★★☆
()
Ответ на: комментарий от qulinxao

нет вложенности возвратов

С этим утверждением не поспоришь.

k0valenk0_igor ★★★
()
Ответ на: комментарий от k0valenk0_igor

Не надо вот так бросаться терминами, нет никакой «задачи» и «параллельности». Ранлуп диспетчит события. Что будет, если «текущий поток», который на самом деле просто текущий хэндлер текущего события, не выйдет до момента, когда придет время таймаута — зависит от реализации setTimeout и того, что в ранлупе под капотом на этот вид события. Мое предположение — скорее вызовется, чем потеряется.

Отсутствие отжирания памяти ничего здесь не объясняет.

arturpub ★★
()
Ответ на: комментарий от makoven

и тут нет рекурсии.

кури как замыкания в языках со сборкой мусора едять и обратное_поеданию_действия память

qulinxao ★★☆
()
Ответ на: комментарий от makoven

Не будет рекурсии тут, если getJSON асинхронная.

Legioner ★★★★★
()
Ответ на: комментарий от makoven

рекурсии тут нет ибо хм.

зависит . тут (предпологая что /get получает откуда то поток данных а процесс_дата их кудато складывает) скорее цикл обработки в виде хвостовой рекурсии.

qulinxao ★★☆
()
Ответ на: комментарий от arturpub

return это от компиляции из кофескрипта остался. Не заметил.

getJSON вторым аргументом ждет функцию которая выполнится при успешном получении данных

makoven ★★★★★
() автор топика
Ответ на: комментарий от arturpub

Доктор, ты чего??

я как всегда проверил этот код в живую. Рекурсия есть. ЧЯДНТ?

А с такой, что по всей видимости func выкидывается из диспетча, и приходится его сувать туда заново по срабатыванию таймаута.

как-то оно через жопу суётся, не находишь?

drBatty ★★
()
Ответ на: комментарий от arturpub

что в любой программе с событийным циклом все точки входа из цикла являются рекурсивными и/или косвенно рекурсивными засчет отложенных и/или псевдоасинхронных действий. Что разумеется не так.

s/программа/быдлокод/

и всё будет правильно. Входить в цикл можно только если из него выйти. Если входишь не выходя, то это рекурсия.

drBatty ★★
()
Ответ на: комментарий от qulinxao

Лично я называю «рекурсией» повторное выполнение кода. ИМХО цикл это тоже рекурсия, просто нынешние CPU лучше умеют циклы, а не хвостовую рекурсию. Что-бы ты там не говорил за преимущества ФП, но факт остаётся фактом: у меня ГЛОБАЛЬНЫЕ 16 регистров внутри CPU. И такая ерунда в 95% компьютеров. Ну а ФП на глобальные контексты совсем не ложится. Потому, что-бы программист не писал, оно всё равно компилятором в цикл переписывается. Т.е. цикл — это и рекурсия тоже.

Что касается «пту-стайла», то вроде в SICP примерно тоже самое и написано, или я что-то не так понял?

drBatty ★★
()
Ответ на: комментарий от drBatty

тогда лично ты называеш рекурсией разделяемый реентерабельный кусок кода - который разделяют одновременно Алиса и Боб . твоя рекурсия замечательна

qulinxao ★★☆
()
Ответ на: комментарий от drBatty

s/программа/быдлокод/

Не распарсил.

Если входишь не выходя, то это рекурсия.

В обоих приведенных примерах входишь выходя.

arturpub ★★
()
Ответ на: комментарий от drBatty

через жопу суётся

Обычное дело, если однократный таймер-источник не выкидывает устаревшие файры. Допустим есть несколько долгоиграющих хэндлеров, как понять в к-л другом месте, что пора еще разок повесить?

arturpub ★★
()

Рекурсии нет. И почему не setInterval?

PolarFox ★★★★★
()
Ответ на: комментарий от Kalashnikov

Мне нужно чтобы в следующий раз функция вызывалась через n секунд после успешного ее выполнения в предыдущий раз.

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

Если посоветуете другой способ решения этой проблемы - буду благодарен. Лично я ничего придумать не могу. Разве что мудрить с евентами или подключать async.js

makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

Чтобы было понятнее - синнхронизация состояния клиента с сервером.

Клиент запрашивает обьект с сервера. Когда объект приходит (всплыло ajax-событие) - ждем секунду, повторяем

makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

Так по логике надо запускаться заново именно через несколько секунд (интервалы кстати в миллисекундах) или после выполнения асинхронного куска? Если второе, то точно надо заморачиваться, интервалы - это костыль, погугли т.н. Promises например.

Kalashnikov ★★★
()
Ответ на: комментарий от Kalashnikov

Здравый смысл подсказывает, что запускать надо спустя некоторое время ПОСЛЕ выполнения коллбека )

Промисы курил. Пока что это это рокет сайнс для меня

makoven ★★★★★
() автор топика
Ответ на: комментарий от rikardoac

Разве? Ведь можно использовать рекурсию и как итерации и как сбор данных и лишь затем будет ее обработка.

дак ведь вырастет не память, а потребление памяти :)

Bad_ptr ★★★★★
()
Ответ на: комментарий от makoven

Мне нужно чтобы в следующий раз функция вызывалась через n секунд после успешного ее выполнения в предыдущий раз.

Все правильно сделал, не переживай.

SetInterval, насколько я понимаю, не гарантирует что предыдущий вызов завершился.

Он тебе второй тред создаст, по-твоему? Конечно гарантирует. Нет никакого «фонового процесса», в котором что-то тикает. Когда ты ставишь таймаут 10 (или интервал 10), внутри ранлупа запоминается, что надо бы стрельнуть колбэком в *или после* «сейчас+10» (или «сейчас+10*n»). Когда управление возвращается ранлупу, т.е. когда выходишь из колбэка, он сверяет текущее время с запомненными значениями и стреляет, если время пришло, только и всего. Причем для «интервала» множественные промежуточные события обычно соединяются в одно последнее, если надолго застрянешь в последнем колбэке.

arturpub ★★
()

Рекурсии тут нет. И даже если в браузере на первый взгляд потребление памяти растет, так это просто еще GC не отработал и браузеру пофиг на использование памяти пока-что

vertexua ★★★★★
()
Ответ на: комментарий от qulinxao

твоя рекурсия замечательна

к счастью она не моя.

drBatty ★★
()
Ответ на: комментарий от qulinxao

п[р]о SICP цитату [cюда]?

а я её давно читал, потому я не помню. А вполне возможно, что спутал :)

drBatty ★★
()
Ответ на: комментарий от arturpub

s/программа/быдлокод/

Не распарсил.

слово у тебя неправильное. S — заменить.

В обоих приведенных примерах входишь выходя.

что-то там какой-то странный «выход» ИМХО. Ну хотя не знаю, вам виднее.

drBatty ★★
()
Ответ на: комментарий от drBatty

Я знаю про регэкспы, ага, я смысл фикса не распарсил.

Ну смотри: вызов func ...передает анонимную функцию в API-функцию, которая инициирует асинхронный запрос и вешает анонимную как его обработчик. Когда обработчик сработает, выполнится process_data(data), а потом вызовется func, который...

Сама func никогда не себя вызывает и выходит сразу после вызова API-функции, которая никогда не вызывает анонимную функцию, которая вызывает func.

arturpub ★★
()
Ответ на: комментарий от drBatty

Лично я называю «рекурсией» повторное выполнение кода. ИМХО цикл это тоже рекурсия

На самом деле, это совсем не так. Главное отличие рекурсии от цикличного исполнения - в контексте. У цикла контекст один и тот же, у рекурсивно вызванного кода - разный. Вот ссылка на вики

Обратите внимание на следующие слова

Реализация рекурсивных вызовов функций в практически применяемых языках и средах программирования, как правило, опирается на механизм стека вызовов — адрес возврата и локальные переменные функции записываются в стек, благодаря чему каждый следующий рекурсивный вызов этой функции пользуется своим набором локальных переменных и за счёт этого работает корректно.

Стек в данном случае и есть контекст.

И в сабже как раз контекст разный. И однако, - qulinxao правильно подметил, - тут нет вложенности возвратов. Так что тут хотя и рекурсия, имхо, но это не декларативная рекурсия, а рекурсия реализации.

k0valenk0_igor ★★★
()
Последнее исправление: k0valenk0_igor (всего исправлений: 2)
Ответ на: комментарий от arturpub

нет никакой «задачи» и «параллельности»

Это как посмотреть. Ну вот посуди сам: рабочий цикл отрабатывает события и доходит до событий, обработчики которых должны быть вызваны одновременно. То есть у событий совершенно одинаковый приоритет. Как быть?

Я подозреваю, что в этом случае js-машина отрабатывает первое событие по времени постановки в очередь, вместо того что бы сделать столько потоков исполнения, сколько задач с одним приоритетом.

Я думаю, так потому, что js-машина должна иметь страховку на случай разростания количества задач до полной попы с ресурсами.

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

Но, конечно, это только мои догадки, - на самом деле надо код машины смотреть

k0valenk0_igor ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.