Comments 78
поменяйте async на non-blocking, пожалуйста.
асинхронность это возможность исполнять несколько действий одновременно, что в рамках однопоточного скрипта невозможно, за исключением воркеров, каждый из которых тоже однопоточный.
асинхронность это возможность исполнять несколько действий одновременно, что в рамках однопоточного скрипта невозможно, за исключением воркеров, каждый из которых тоже однопоточный.
+9
Ох, война терминологии :). Кстати, практически везде начинает использоваться бренд «async», тут как с HTML5, наверное придётся смириться :).
0
UFO just landed and posted this here
Некоторые функции «блокируются»: например, чтение килобайта через медленное соединение может подвесить прогу. В таких случаях нужно уметь делать что-то параллельно, не дожидаясь результата. Да и одноядерные процессоры умеют переключать контекст исполнения между thread'ами и процессами.
+3
Хорошая статья, давно пора на Хабре больше умного писать и меньше перепечатки новостей :)
Я только не понял идею Do. Что мешает вместо
Я только не понял идею Do. Что мешает вместо
continuableFunc(args)(doSomething, errorHandler)
писать continuableFunc(args, doSomething, errorHandler);
без всяких умных слов и чуть короче? :)+10
Где-то в примерах была уже реализация асинхронности через yield, подобная ADISP.
Не можете подсказать линк?
Не можете подсказать линк?
0
Насчёт python и неблокирующего нетворкинга смотрим на gevent.org — почти идеальное решение ;-).
+2
Почти. Gevent — это Eventlet, сделанный правильно, но неправильно.
Что правильно:
1. Один способ опрашивать ядро (libevent).
2. Быстрый мейнлуп на C (libevent).
3. Сохранены интерфейсы Event, Queue, Semaphore.
Что неправильно:
1. libevent (надо было libev)
2. Отсутствует возможность патчить socket и прочие модули, чтобы работал нормальный синхронный код. Это есть в eventlet.
Что неправильно в Eventlet:
1. Много способов опрашивать события (хабы: select, epoll, libevent, libev, правда последний давно не поддерживается и выкинут из сорцов).
2. Мейнлуп на питоне (частично из-за пункта 1).
Что правильно:
1. Один способ опрашивать ядро (libevent).
2. Быстрый мейнлуп на C (libevent).
3. Сохранены интерфейсы Event, Queue, Semaphore.
Что неправильно:
1. libevent (надо было libev)
2. Отсутствует возможность патчить socket и прочие модули, чтобы работал нормальный синхронный код. Это есть в eventlet.
Что неправильно в Eventlet:
1. Много способов опрашивать события (хабы: select, epoll, libevent, libev, правда последний давно не поддерживается и выкинут из сорцов).
2. Мейнлуп на питоне (частично из-за пункта 1).
+2
3. Отклонения от стандартных интерфейсов Event, Queue, Semaphore. Особенно Event.
0
> Что неправильно:
> 1. libevent (надо было libev)
На самом деле все бенчмарки libev относительно libevent очень стары, никто не делал сравнений с новыми версиями. Libevent более распространён (memcached, chromium, ...) и более стабилен, к тому же там есть httpd, httpc, асинхронный револьвер DNS. Я бы не сказал libev более уместен тут.
> 2. Отсутствует возможность патчить socket и прочие модули, чтобы работал
> нормальный синхронный код. Это есть в eventlet.
Такая возможность есть — модуль gevent.monkey.
> 1. libevent (надо было libev)
На самом деле все бенчмарки libev относительно libevent очень стары, никто не делал сравнений с новыми версиями. Libevent более распространён (memcached, chromium, ...) и более стабилен, к тому же там есть httpd, httpc, асинхронный револьвер DNS. Я бы не сказал libev более уместен тут.
> 2. Отсутствует возможность патчить socket и прочие модули, чтобы работал
> нормальный синхронный код. Это есть в eventlet.
Такая возможность есть — модуль gevent.monkey.
0
0
Если честно, то цифры в бенчмарке несколько странные.
0
Бенчмарк действительно очень полный, в отличие от приведенного мною. Признаться, не хотел свести все к сравнению питонячих веб-серверов.
Вспомнил, что разработчик fapws в 3-й версии отказался от libevent в пользу libev (должно быть не зря). Наверное корректнее было посмотреть бенчмарк fapws2 vs fapws3, хотя на результаты скорее всего сильно повлияет другая база кода.
Вспомнил, что разработчик fapws в 3-й версии отказался от libevent в пользу libev (должно быть не зря). Наверное корректнее было посмотреть бенчмарк fapws2 vs fapws3, хотя на результаты скорее всего сильно повлияет другая база кода.
0
Майкры работают над Async Workflows, вот так это выглядит:
let file = File.OpenRead(«Program.fs»)
let! stuff = file.AsyncRead(250) // Тут считывается файл, неблокируя и асинхронно
printfn "%A" (Encoding.Default.GetString(stuff)) // А тут синхронно печатается в консольку
let req = WebRequest.Create(«www.google.com/search?q=node.js»)
let! resp = req.AsyncGetResponse() // Тут скачивается НТМЛ, тож неблокируя и асинхронно
printfn "%i headers recieved." resp.Headers.Count // Опять синхронно печатается в консольку
Это F#. Все асинхронно, и все неблочаще. Доступно уже года два или больше.
Я у себя в блоге (http://chaliy.name/blog/2010/7/node_dot_net) всегото пару дней тому назад возмущался, что node.js аж нисколечки нечетабельный.
let file = File.OpenRead(«Program.fs»)
let! stuff = file.AsyncRead(250) // Тут считывается файл, неблокируя и асинхронно
printfn "%A" (Encoding.Default.GetString(stuff)) // А тут синхронно печатается в консольку
let req = WebRequest.Create(«www.google.com/search?q=node.js»)
let! resp = req.AsyncGetResponse() // Тут скачивается НТМЛ, тож неблокируя и асинхронно
printfn "%i headers recieved." resp.Headers.Count // Опять синхронно печатается в консольку
Это F#. Все асинхронно, и все неблочаще. Доступно уже года два или больше.
Я у себя в блоге (http://chaliy.name/blog/2010/7/node_dot_net) всегото пару дней тому назад возмущался, что node.js аж нисколечки нечетабельный.
+3
Не совсем честно сравнивать спец. ЯП :), у автора в статье тоже есть примеры, да и новые ЯП со встроенной асинх. давно есть.
-1
Это F#, язык общего назначения, с функциональным уклоном. Эти воркфлоу реализованы стандартными средствами языка. Средство называется Computation Expressions.
0
Немного поклобасило код, тут наверное будет удобней смотреть gist.github.com/492365
0
Ну что скажешь, молодцы. Хотя могли бы и элегантнее :-)
0
Да мне тож так кажется. Например восклицательный знак из let прибрать, слово Async. Но фишка в том что это заимплеменчено стандарными сердствами языка. Тоесть теоретически такую же штуку можно провернуть, чтобы запустить этот код на разных машинах. Или например что-бы вставить туда MSMQ. Или сделать его выполняем в браузере (компилится в javascript — WebSharper). Или… масса применений.
0
Erlang прекрасен!
-1
В плане асинхронности — да.
Но там будут свои геморрои — например, меньше полезных либ, некоторые кривые, поэтому какие-то очевидные вещи, которые на js/python/etc… делаются сходу, здесь потребуют времени.
Но там будут свои геморрои — например, меньше полезных либ, некоторые кривые, поэтому какие-то очевидные вещи, которые на js/python/etc… делаются сходу, здесь потребуют времени.
0
надеюсь в fprog появиться эта статья, а пока можно почитать только это:
node.js vs. Erlang — groups.google.com/group/erlang-russian/browse_thread/thread/cf3c65b0c5230834
>Но там будут свои геморрои
так везде есть свои проблемы, область применимости и требования к качеству конечного продукта
ps я в эрланге ни бум бум, кроме написания hello world :) но язык концептуально меня поразил больше чем node.js
node.js vs. Erlang — groups.google.com/group/erlang-russian/browse_thread/thread/cf3c65b0c5230834
>Но там будут свои геморрои
так везде есть свои проблемы, область применимости и требования к качеству конечного продукта
ps я в эрланге ни бум бум, кроме написания hello world :) но язык концептуально меня поразил больше чем node.js
0
Erlang — простой, надежный, но ограниченный язык
JS куда более универсален
PS Я в Erlang'e бум-бум :-)
JS куда более универсален
PS Я в Erlang'e бум-бум :-)
+1
какие ограничения есть у этого языка?
0
Огромное количество очень суровых ограничений, именно в них его сила.
Отсутствие деструктивного присваивания, немутируемые в принципе данные, общение между потоками только посылкой сообщений, на каждом шагу возникает необходимость создания компонентов в виде мини-серверов, ужасающая рудиментарная поддержка объектности… Список можно продолжить.
Эти ограничения заставляют решать задачи определенным способом, который как правило и является правильным, если только вы не пытаетесь сделать что-то, для чего язык совершенно не предназначен. Но это ограничивает область его применения.
Да что тут рассуждать, напишите на эрланге пару-тройку проектов, хотя бы и учебных — это даст вам понимания на два порядка больше чем самая заумная статья.
Отсутствие деструктивного присваивания, немутируемые в принципе данные, общение между потоками только посылкой сообщений, на каждом шагу возникает необходимость создания компонентов в виде мини-серверов, ужасающая рудиментарная поддержка объектности… Список можно продолжить.
Эти ограничения заставляют решать задачи определенным способом, который как правило и является правильным, если только вы не пытаетесь сделать что-то, для чего язык совершенно не предназначен. Но это ограничивает область его применения.
Да что тут рассуждать, напишите на эрланге пару-тройку проектов, хотя бы и учебных — это даст вам понимания на два порядка больше чем самая заумная статья.
+1
Erlang прекрасен в своей нише
+1
хорошо, тогда какая ниша у ерланга и ноды?
0
Erlang — в первую очередь телеком и все виды стэйт машин. Вот GUI на нем не попишешь — полное безобразие получается, взгляните хотя бы на его обертки к wxWidgets. Вообще, любые задачи с состоянием в виде развесистого сильно мутабельного по своей природе дерева делать на эрланге — мучение.
Про ноду говорить не совсем верно, правильнее про JS. А он зарекомендовал себя как вполне универсальный — чего только на нем не пишется и все вполне удобно и успешно. И серверные решения, и GUI, и злая математика. Основная проблема была в скорости, но V8 хорошо подсобил.
Про ноду говорить не совсем верно, правильнее про JS. А он зарекомендовал себя как вполне универсальный — чего только на нем не пишется и все вполне удобно и успешно. И серверные решения, и GUI, и злая математика. Основная проблема была в скорости, но V8 хорошо подсобил.
+1
В руби 1.9 можно писать синхронный код используя non-blocking вызововы, достигается это благодаря связке EventMachine + Fibers. Подробней об этой технике можно почитать тут. Есть даже рельсы, которые используют non-blocking io — github.com/igrigorik/async-rails
+2
Первая ссылка попортилась. Вот правильная: www.igvita.com/2010/03/22/untangling-evented-code-with-ruby-fibers
0
Вспомнилась жуткая JS-библиотечка Concurrent.Thread
jsthread.sourceforge.net/
Статья авторов на английском в pdf тут.
Треды там условные, но она как раз позволяет писать асинхронный (неблокирующий) код в синхронном стиле. Как это работает? Ваши функции вычитываются в строку через Function.prototype.toString, перепарсиваются, циклы разматываются в goto-style, и в некоторых местах вставляется вызов, передающий управление таск-свитчеру. Затем это снова превращается в функции (то ли через new Function, то ли через eval). В статье есть пример с Ajax-запросом. Страшные тормоза, но красивый код =) Если узкое место — это связь с сервером по Ajax, то эту радость теоретически даже можно использовать. Я сам не пробовал :-)
jsthread.sourceforge.net/
Статья авторов на английском в pdf тут.
Треды там условные, но она как раз позволяет писать асинхронный (неблокирующий) код в синхронном стиле. Как это работает? Ваши функции вычитываются в строку через Function.prototype.toString, перепарсиваются, циклы разматываются в goto-style, и в некоторых местах вставляется вызов, передающий управление таск-свитчеру. Затем это снова превращается в функции (то ли через new Function, то ли через eval). В статье есть пример с Ajax-запросом. Страшные тормоза, но красивый код =) Если узкое место — это связь с сервером по Ajax, то эту радость теоретически даже можно использовать. Я сам не пробовал :-)
+2
На мой взгляд, система колбэков — не самая большая проблема неблокирующих вызовов.
Главная проблема — работа с состоянием программы (переменные). Если представить себе программу в виде графа с вершинами-состояниями (она им и является), то обычная синхронная программа описывается более или менее читаемо. На вершинах обычно пишут изменения вектора состояния, предполагая остальные переменные — инвариантами относительно соседних состояний.
А вот когда мы связываемся с неблокирующими вызовами колбэков, это, фактически, может означать что ЛЮБОЙ обработчик может быть вызыван при ЛЮБОМ векторе состояний. Мы, фактически, теряем вообще все инварианты в программе!
Задумайтесь!
Раньше в обработчике вы делали проверку нескольких условий, предполагая, что все остальные вещи будут именно в том виде, как следует (ведь мы гарантируем это в предыдущем коде).
В неблокирующих вызовах инвариантов нет.
Обработчик должен проверять туеву хучу состояний, чтобы удостовериться: да, мыжно выполнить обработку в том или ином виде.
Хотите наглядный пример?
В яваскрипте загружаю набор данных со стороннего сервера. JQuery::json. И всё бы хорошо, но выборку данных формирует пользователь через интерфейс. К тому времени, когда данные придут, пользователь может нащёлкать интерфейс, много чего поменяв в выборке. В обработчике приходится полностью проверять состояние интерфейса и срочно придумывать что из полученной выборки пригодится, если требования пользователя изменились.
И хорошо если интерфейс описывается 2-3 переменными. Когда настроек много, то есть длинный вектор состояний запросов, проверка всего длинного вектора и принятие решение о дополнительной обработке выборки — много дополнительного анализа и работы по его реализации.
Главная проблема — работа с состоянием программы (переменные). Если представить себе программу в виде графа с вершинами-состояниями (она им и является), то обычная синхронная программа описывается более или менее читаемо. На вершинах обычно пишут изменения вектора состояния, предполагая остальные переменные — инвариантами относительно соседних состояний.
А вот когда мы связываемся с неблокирующими вызовами колбэков, это, фактически, может означать что ЛЮБОЙ обработчик может быть вызыван при ЛЮБОМ векторе состояний. Мы, фактически, теряем вообще все инварианты в программе!
Задумайтесь!
Раньше в обработчике вы делали проверку нескольких условий, предполагая, что все остальные вещи будут именно в том виде, как следует (ведь мы гарантируем это в предыдущем коде).
В неблокирующих вызовах инвариантов нет.
Обработчик должен проверять туеву хучу состояний, чтобы удостовериться: да, мыжно выполнить обработку в том или ином виде.
Хотите наглядный пример?
В яваскрипте загружаю набор данных со стороннего сервера. JQuery::json. И всё бы хорошо, но выборку данных формирует пользователь через интерфейс. К тому времени, когда данные придут, пользователь может нащёлкать интерфейс, много чего поменяв в выборке. В обработчике приходится полностью проверять состояние интерфейса и срочно придумывать что из полученной выборки пригодится, если требования пользователя изменились.
И хорошо если интерфейс описывается 2-3 переменными. Когда настроек много, то есть длинный вектор состояний запросов, проверка всего длинного вектора и принятие решение о дополнительной обработке выборки — много дополнительного анализа и работы по его реализации.
+4
Мне кажется вы думаете не в ту сторону. Не надо требовать от технологии то, для чего она не предназначена — в данном случае для уточнения выборки. Либо оптимизируйте серверную часть, чтобы все выглядело красиво, либо просто делайте новую выборку не показывая старую, если состояние интерфейса изменилось.
+1
Я привёл довольно «щадящий» пример. Проблема на самом деле гораздо серьёзнее.
Когда пишете любую функцию, подумайте, сколько переменных вы считаете инвариантами.
А теперь представьте, что инвариантов больше нет.
И вам надо (в общем случае) проверять все переменные.
Например, к моменту вызова обработчика может идти шатдаун интерфейса; или идёт фильтрация предыдущих данных. Да всё что угодно может быть.
Когда пишете любую функцию, подумайте, сколько переменных вы считаете инвариантами.
А теперь представьте, что инвариантов больше нет.
И вам надо (в общем случае) проверять все переменные.
Например, к моменту вызова обработчика может идти шатдаун интерфейса; или идёт фильтрация предыдущих данных. Да всё что угодно может быть.
+2
Да нет той проблемы, о которой вы пишете.
При правильной архитектуре каждый конкретный кусок кода имеет дело лишь с частью состояния, на остальное ему плевать. И эта часть не должна быть слишком большой.
Это и дает возможность существовать языкам, в которых данные как правило вообще немутабельны (взять тот же Erlang, к примеру).
Если вам действительно нужно разруливать кучу взаимозависимых состояний и сложно понять, с какого конца может пойти волна изменений — посмотрите подходы, применяемые в акторном прологе. Но это имеет смысл только для весьма специфических задач, в большинстве случаев лучше быть проще.
Что касается вашего примера, простейшее решение — перезапрос. Желание использовать результаты прошлой выборки для текущего состояния — это попытка жесткой оптимизации, как правило не оправданная.
При правильной архитектуре каждый конкретный кусок кода имеет дело лишь с частью состояния, на остальное ему плевать. И эта часть не должна быть слишком большой.
Это и дает возможность существовать языкам, в которых данные как правило вообще немутабельны (взять тот же Erlang, к примеру).
Если вам действительно нужно разруливать кучу взаимозависимых состояний и сложно понять, с какого конца может пойти волна изменений — посмотрите подходы, применяемые в акторном прологе. Но это имеет смысл только для весьма специфических задач, в большинстве случаев лучше быть проще.
Что касается вашего примера, простейшее решение — перезапрос. Желание использовать результаты прошлой выборки для текущего состояния — это попытка жесткой оптимизации, как правило не оправданная.
+1
Вы же сами пишете: «при правильной архитектуре». Синтаксис языка никак эту структуру не обуславливает. Значит, проблема всё-таки есть.
Сформулируем ещё раз: проблема создания правильной архитектуры несинхронных программ: неблокирующих (попроще) и асинхронных (посложнее).
Я был бы признателен, если вы напишете продолжение вашей статьи, где бы подробно описали эту архитектуру и детали её проектирования.
К примеру, для асинхронных программ, мне очень нравится подход Эрланга, который разделяет переменные потоков. Очень нравится система обмена сообщениями через очередь.
Нравится настолько, чтопереизобрёл велосипед написал на С++ и оптимизировал кроссплатформенный класс потока с асинхронными очередями. Только им и пользуюсь, общие переменные между классами для себя исключил, после чего проблем с многопоточностью на С++ стало на порядок меньше (если это не высокопроизводительный сервер).
Но всё не даётся даром. Через какое-то время я ощутил, что подобный подход требует более серьёзной работы с инвариантами. Их, в отличие от внутренних переменных потока, нельзя изолировать от обработчика, потому что это вектор состояния потока-обработчика, а не вектор потока-инициатора сообщения. Я прихожу ко мнению, что асинхронная очередь сообщений (колбэков), вполне возможно, предполагает стэковую организацию векторов состояний потоков. В общем, это большая тема. И если у вас есть знания и серьёзные наработки в этой области, я бы с огромным интересом почитал вашу статью.
Сформулируем ещё раз: проблема создания правильной архитектуры несинхронных программ: неблокирующих (попроще) и асинхронных (посложнее).
Я был бы признателен, если вы напишете продолжение вашей статьи, где бы подробно описали эту архитектуру и детали её проектирования.
К примеру, для асинхронных программ, мне очень нравится подход Эрланга, который разделяет переменные потоков. Очень нравится система обмена сообщениями через очередь.
Нравится настолько, что
Но всё не даётся даром. Через какое-то время я ощутил, что подобный подход требует более серьёзной работы с инвариантами. Их, в отличие от внутренних переменных потока, нельзя изолировать от обработчика, потому что это вектор состояния потока-обработчика, а не вектор потока-инициатора сообщения. Я прихожу ко мнению, что асинхронная очередь сообщений (колбэков), вполне возможно, предполагает стэковую организацию векторов состояний потоков. В общем, это большая тема. И если у вас есть знания и серьёзные наработки в этой области, я бы с огромным интересом почитал вашу статью.
0
Проблемы нет, потому что есть подходы, наработки и традиции, которые позволяют строить архитектуру правильно. Что такое «правильно» — сильно зависит от проекта, поэтому тут лучше говорить предметно.
Вы говорите, вам понравился подход Erlang'а — замечательно, используйте его. Erlang обеспечивает полную изоляцию переменных, запрещая даже простейшее деструктивное присваивание — изолировано все от всего, не важно внутреннее оно или принадлежит обработчику. Для нормальной скорости работы это требует суровых оптимизаций, copy-on-write — наверное самая примитивная из них.
На C++ такое реализовать будет непросто. Но запрещать принципиальную возможность «сделать не так» не обязательно, часто достаточно соглашений. Или используйте языки со встроенным нужным подходом — Erlang далеко не единственный предоставляет изоляцию, почти любой язык из семейства функциональных поступает подобным образом. Почитайте доклад Валкина, может под ваши задачи хорошо ляжет тот же OCaml. На C++ свет клином не сошелся.
Вы говорите, вам понравился подход Erlang'а — замечательно, используйте его. Erlang обеспечивает полную изоляцию переменных, запрещая даже простейшее деструктивное присваивание — изолировано все от всего, не важно внутреннее оно или принадлежит обработчику. Для нормальной скорости работы это требует суровых оптимизаций, copy-on-write — наверное самая примитивная из них.
На C++ такое реализовать будет непросто. Но запрещать принципиальную возможность «сделать не так» не обязательно, часто достаточно соглашений. Или используйте языки со встроенным нужным подходом — Erlang далеко не единственный предоставляет изоляцию, почти любой язык из семейства функциональных поступает подобным образом. Почитайте доклад Валкина, может под ваши задачи хорошо ляжет тот же OCaml. На C++ свет клином не сошелся.
0
Я каждый раз когда смотрю на node.js вижу одну большую монаду на ручной тяге :-)
0
а зачем вы нарочно нечестно устрашили первый пример? ведь в синхронном вызове ничего не говорилось об обработке ошибок. некрасивый психологический трюк.
я лично со временем так привык к асинхронности, что практически её не замечаю, сидит в мозгу, как родная
я лично со временем так привык к асинхронности, что практически её не замечаю, сидит в мозгу, как родная
var f = syncOpen(args); checkConditions(f); var result = syncReadAll(f); checkResult(result); asyncOpen(args, function(f){ checkConditions(f); asyncReadAll(f, function(result){ checkResult(result); }); });
+4
— Синхронный вызов ожидаемо кинет исключение, а в асинхронном я должен сделать это руками, так что никакого «нарочно нечестно»
— Даже если забить на обработку ошибок, это не отменяет описанной проблемы
А в простых случаях — да, даже существующий синтаксис вполне приемлим.
— Даже если забить на обработку ошибок, это не отменяет описанной проблемы
А в простых случаях — да, даже существующий синтаксис вполне приемлим.
0
Кстати, по-моему у Ruby и Coffeescript самая красивая и короткая лямбда, что важно при асинхронном коде.
Ruby:
Coffeescript:
Ruby:
asyncOpen('file') { |file| file.read { |content| checkResult(content) } }
Coffeescript:
asyncOpen ''file', (file) => file.read (content) => checkResult(content)
0
В Actionscript3 практически всё основано на асинхронных событиях — ничего с читабельностью не случается — код понятен и читаем. А вот анонимные коллбэки — зло.
И не надо говорить что AS3- однопоточен — это не имеет значения.
В C# тоже очень удобно сделаны события (сигнал-слот)
Асинхронность помогает читабельности. А вот анонимные функции в javascript надо вообще отменить отдельным указом — с расстрелом за невыполнение.
Была же классная спека ES4 — почему остались на убогом ES3.5?
И не надо говорить что AS3- однопоточен — это не имеет значения.
В C# тоже очень удобно сделаны события (сигнал-слот)
Асинхронность помогает читабельности. А вот анонимные функции в javascript надо вообще отменить отдельным указом — с расстрелом за невыполнение.
Была же классная спека ES4 — почему остались на убогом ES3.5?
0
чем вам не нравятся анонимные функции в Javascript? так, чисто любопытно
+3
Позвольте я встряну… Тем, что во многом они делают один и тот же функционал, но тело их каждый раз целиком указано в каждом вызове. Анонимность вообще во многом зло — когда пишешь сам, она терпима, но когда код коммитишь (показываешь другим) — зло, зло, зло. Потому что вместо того, чтобы вчитываться в логику работы программы, вчитываешься в скобочки. И получается за деревьями не видно леса.
Особенно в такую жару =) Буквально вчера рефакторил полдня, чтобы и без того убитый мозг мог хоть как-то читать.
Особенно в такую жару =) Буквально вчера рефакторил полдня, чтобы и без того убитый мозг мог хоть как-то читать.
0
а чем плоха анонимная ф-ция, если она не повторяется и не собирается повторятся?
+1
Если она действительно не повторится — ничем.
Но такое бывает крайне редко, к сожалению. В основном есть куча перенагруженного кода.
Но такое бывает крайне редко, к сожалению. В основном есть куча перенагруженного кода.
0
я сейчас разрабатываю приложение. там куча таких анонимных ф-ций, которые никогда не повторятся. но такие вещи на жс режко разрабатываются, да
+1
Навешивание событий (как в jQuery) предполагает большое кол-во анонимных функций, которые не повторяются.
0
Практически в любом языке, к. поддерживает анонимные объявления и события, события можно объявлять так. Вот только почти в каждой книге а-ля «совершенный код» или там «лучшие практики» такого подхода советуют не придерживаться.
Но это уже совсем не касается предмета разговора и ведет на скользскую дорожку холивара. =)
Но это уже совсем не касается предмета разговора и ведет на скользскую дорожку холивара. =)
0
Странные вы книги читали ;). В Java и C# нверное не рекомендуется. В Ruby анонимными функциями даже по массиву ходят вместо foreach. В тех же рекомендациях по jQuery тоже самое — везде анонимки. В языках, где широко применяется функции высшего порядка из ФП (map, each, filter) точно так же рекомендуют использовать именно эти функции, то есть передавать логику обработки массива, как анонимную функцию.
0
Почему же сразу страшные? Совершенно верно: как раз по Java. =)
У меня оттуда и сохранилась привычка — сохранять как можно меньше анонимности. Конечно, создавать отдельный класс ради 3 строк — глупость, но если там хотя бы одно ветвление…
Я слишком радикально написал. Ниже (сейчас прямо под моим комментарием), dimsmol написал лучше некуда: «Анонимные колбэки — очень большое добро при правильном использовании».
У меня оттуда и сохранилась привычка — сохранять как можно меньше анонимности. Конечно, создавать отдельный класс ради 3 строк — глупость, но если там хотя бы одно ветвление…
Я слишком радикально написал. Ниже (сейчас прямо под моим комментарием), dimsmol написал лучше некуда: «Анонимные колбэки — очень большое добро при правильном использовании».
0
Ох, странные у меня мутировали в страшные, но не суть.
0
Ну так у Java совсем другая идеология и подход. Не надо его распространять на Javascript и другие динамические ЯП. Ну как бы нет абсолютных истин. Есть несколько набор вещей, которые друг с другом уживаются. У динамических ЯП один набор истин, у Java/C# другая.
Меня например очень смущают, когда в JS тянут идеологию Java — получаются монстры типа ExtJS. JS ближе к Ruby/Python, чем к Java.
Меня например очень смущают, когда в JS тянут идеологию Java — получаются монстры типа ExtJS. JS ближе к Ruby/Python, чем к Java.
0
Когда я смотрел на JS со стороны опыта на Java, то JS мне не нравился. Но когда я увидел jQuery, то почувствовал прекрасную и стройную философию JS, которую теперь люблю (хотя у языка есть много слабых мест, типа длинного синтаксиса и отсутствия method_missing).
А ещё меня смущает, что из-за образования в универе Pascal→C→Java программисты не знают о существовании других философий языка, типа ФП с LISP и т. д.
А ещё меня смущает, что из-за образования в универе Pascal→C→Java программисты не знают о существовании других философий языка, типа ФП с LISP и т. д.
0
Анонимные колбэки — очень большое добро при правильном использовании. У меня куча кода под рукой, который без них выглядел бы куда более страшно и убого.
Сигнал-слот — хорошая абстракция, но тяжеловесная, не всегда удобная.
Всему свое место.
Сигнал-слот — хорошая абстракция, но тяжеловесная, не всегда удобная.
Всему свое место.
0
Кажется вам нехватает знания понятий со-процедуры (co-procedures) и продолжения (continuations), через которые они реализуются.
+1
>> со-процедуры (co-procedures)
вы про сопрограммы (coroutines)?
>> и продолжения (continuations), через которые они реализуются.
сопрограммы необязательно реализовывают через continuations.
и вообще это совершенно другой подход: сопрограммы — это кооперативная многозадачность.
вы про сопрограммы (coroutines)?
>> и продолжения (continuations), через которые они реализуются.
сопрограммы необязательно реализовывают через continuations.
и вообще это совершенно другой подход: сопрограммы — это кооперативная многозадачность.
0
Как знание или незнание этих понятий влияет на описанные в статье проблемы?
Есть конструктивные предложения?
Есть конструктивные предложения?
0
Основная засада — синхронный код, приведенный выше, замечательно читается.
Заранее извиняюсь за своё не слишком профессиональное в этих вопросах мнение, но по-моему это говорит о том, что нужен новый язык, в котором всё было бы асинхронно само по себе и всем этим расписыванием занимался бы компилятор/интерпретатор.
+1
> фактически прервет исполнение в точке вызова и когда-нибудь начнет его снова из этой же точки, используя сохраненный контекст
Я может чего-то не понимаю, но это просто описание синхронного программирования фактически :))
Поскольку продолжать исполнение будет ровно тот, кого мы запустили асинхронно и никто другой (нам нужны именно те данные результата, которые только он возвращает.
Другими словами нужно просто весь этот синхронный кусок из 4х синхронных вызовов выделить в отдельный асинхронный поток средствами языка или библиотек. Разве нет?
Или вы предполагаете что этот сохраненный контекст кто-то другой сможет использовать в другом месте? Пока представляется только режим отладчика, который может возобновлять выполнение в разрез с задуманной заранее последовательностью действий.
Я может чего-то не понимаю, но это просто описание синхронного программирования фактически :))
Поскольку продолжать исполнение будет ровно тот, кого мы запустили асинхронно и никто другой (нам нужны именно те данные результата, которые только он возвращает.
Другими словами нужно просто весь этот синхронный кусок из 4х синхронных вызовов выделить в отдельный асинхронный поток средствами языка или библиотек. Разве нет?
Или вы предполагаете что этот сохраненный контекст кто-то другой сможет использовать в другом месте? Пока представляется только режим отладчика, который может возобновлять выполнение в разрез с задуманной заранее последовательностью действий.
0
Проблема в том, что исполняющий движок что JS, что питона, что многих других языков, в текущей реализации будет ждать возврата из библиотечной функции, заблокировав исполнение в том числе других нитей — в каждый момент времени только одна нить может что-то делать и она «как-бы делает». Неблокирующие вызовы должны позволить продолжать исполнение других нитей во время ожидания ввода-вывода и прочего подобного, когда на самом ничего могущего помешать другим нитям не происходит.
+1
Sign up to leave a comment.
Асинхронность: почему это никак не сделают правильно?