Pull to refresh

Comments 105

Подскажите, есть какие мосты между node.js (server-side javascript) и Python/Ruby/…?
Пока не встречал, но так как они были бы крайне полезны, уверен будут написаны… На мой взгляд сообщество у node маленькое но очень активное…
Вот тут мне посоветовали посмотреть на pyv8. Но как я понял работает напрямую с движкой v8, а node.js это вроде бы как врапер на v8. Вообщем как-то все запутанно и много если…
Ну да… но подключение nodejs из python врядли когданибудь будет, ведь node представляет собой приложение а не библиотеку… а вот наоборот, подключение кода на питоне из node уверен появится… например для возможности из node использовать библиотеки для питона…
А смысл? Зачем два языка? Тогда сразу все — и на js.
чтобы можно было в node использовать библиотеки python что-нибудь вроде:
twisted=py.require('twisted');
twisted.…

Возможно, если будет выходной без интернета (и работы соответственно) напишу такую штуку…
Слишком много будет несовпадений по типам данных имхо.
Возможно… а может быть будет достаточно конвертора для строк, чисел, списков, массивов, и рекурсивного конвертора для объектов… поковыряться можно будет в этой области…
Можно сделать какой-то API поверх http да и все. REST и тд. Потом при желании можно будет на разные серверы разнести.
В Ruby есть библиотека EventMachine как раз event-loop + неблокирующий IO. Есть веб-сервер thin использующий эту библиотеку. Для питона есть Twisted.
Если проект уже на питоне или руби то думаю лучше посмотреть в сторону их «родных» средств, чем плодить зоопарк из разных зверей)))
nodejs — цаца, это да.

Интересно, а если на Twisted сделать с их deferred? Тогда не будет блокирующего sleep, если я все правильно понимаю
Ну скорее нужно просто сделать неблокирующий sleep, неблокирующую работу с бд и.т.д,
единственное в чём будет минус питона — что там на так наглядно будут выглядеть каллбэки.
Я думаю, что реальная разница js и python здесь — полноценные анонимные функции.

Нечто подобное можно наколдовать на greenlets, stackless python и еще чем-то, чьи названия вспомнить сходу не удается; разница будет только в синтаксисе (используются ли генераторы, coroutines, легковесные процессы и так далее). Там ж в глубине всего — те же самые неблокирующие сокеты типа как в epoll, а они одни на всех.

Да и, опять же, nodejs — низкоуровневое решение. Клево было бы увидеть фреймворк, который бы позволил полномасштабно использовать все эти фишки в рамках единой технологии.

Например, я слышал про патч для php, позволяющий возвращать ответ на запрос — и продолжать работу. В любимом Джанго и спецификации wsgi вообще ничего подобного, к сожалению, нетуть.
Чего не хватает джаваскрипту, чтобы превратиться в идеальное решение для написания асинхронных приложений (в том числе AJAX), так это поддержки продолжений на уровне языка, чтобы можно было писать асинхронный код линейно, а не с помощью огромного количества вложеных замыканий.

Переписать node.js на Scheme, что ли :)
В Javascript можно писать в стиле Continuations. Примерно так как это сделано в некоторых местах в jQuery. Это скорее вопрос стиля программирования, Javascript как язык позволяет такое без проблем.
Конечно, можно. function в 4-й строке — самый что ни на есть continuation.

Однако на уровне языке продолжений как объектов первого класса нет, их приходится делать самому, вставляя в нужных местах function и скобочки. А вот в Scheme — есть. См. call-with-current-continuation. en.wikipedia.org/wiki/Call-with-current-continuation

Точно так же в C нет поддержки замыканий. Их, конечно, можно сделать с помощью указателей на функции, передавая им enironment в виде структуры, и можно даже говорить, что это «скорее вопрос стиля программирования»… Но это не значит, что там замыкания есть.
С этим всё хорошо, никто не заставляет вас в каллбэк пихать именно функцию целиком, более того на node вы можете написать даже так:

query(' ... ', require('some js file').callback1);

Тут всё дело в навыках проектирования… В некоторых случаях лучше вложить ассинхронный код, а в некоторых лучше написать линейно, однако возможность вложить — часто облегчает жизнь…
Меня заставляет делать это логика приложения ;)

Хорошо, попробую совсем разжевать. С помощью продолжений, встроенных в реализацию, можно написать:

var a = stream.readline();
var b = stream.readline();
var c = a + b;


при этом оба вызова будут асинхронными, но второй readln будет вызван строго после того, как выполнится первый.

При этом в языке без поддержки продолжений придётся выписать их явно:

stream.readline(function (a) {
stream.readline(function (b) {
var c = a + b;

};
});

Почувствуйте разницу.
(Тег pre я указал, но парсер его съел, поэтому код не форматирован).
Да, не правильно вас понял с начала, если честно не слышал про продолжения… это довольно заманчиво… Я с Вами согласен… А есть ли поддержка продолжений где-нибудь кроме Scheme?
Спасибо! вот этого действительно JS очень нехватает… Но такой возможности скорее всего никогда не появится, как бы быстро вэб стандарты не двигались =(
Пусть хотя бы добавят в v8, и то будет большой прогресс :)

Если я правильно помню, в новый стандарт ECMAscript продолжения не вошли из-за давления Microsoft, т.к. их нельзя эффективно реализовать на .NET (я имею в виду Jscript .NET). Опять виновата Microsoft :) хотя, возможно, и другие вендоры были не очень рады.

Но не всё потеряно — есть несколько Source-to-Source компиляторов Javascript. Не знаю, удастся ли их использовать вместе с node.js, всё собираюсь попробовать:

www.neilmix.com/narrativejs/doc/
chumsley.org/jwacs/
Тоесть эти компиляторы компирируют JS код с продолжениями в обычный js код?
Да, но тут возникает такая проблема: формально CPS-преобразование глобальное, и компиляторам нужно знать, внутри каких функций используются продолжения (прямо или опосредованно), а внутри каких — нет. А без этого знания компилятор преобразует вызовы request.sendBody/sendHeader и других библиотечных вызовов (но не сами библиотечные функции, естественно).

Так что надо пробовать, смотреть, какой код генерируют эти компиляторы и можно ли указать функции, которые конвертировать не надо (или, может быть, компилятор не конвертирует функции, про которые ничего не знает, но в этом случае тоже будут проблемы).
Ага, Concurrent.Thread, на который я сослался ниже, как раз позволяет писать такой код :-)
У Javascript-программистов с асинхронностью проблем нет, они привыкли в таком стиле писать скрипты. Обращения к серверу асинхронные, новомодный confirm красивым div'ом асинхронный, обращение к sqlite в Safari асинхронное.
А если вы не умеете писать асинхронный код без огромного количества вложенных замыканий, то это ведь проблема не языка, правильно? На PHP нечитаемый код пишут, пожалуй, чаще (ну просто на нём вообще пишут чаще), но это же никого не останавливает писать на нём нормальный код.
2) Для выполнения Javascript используется движок V8 от Google, который работает довольно быстро благодаря компиляции в машинный код перед выполнением.

Машинный код или опкод?
В английской версии вики написано bytecode. А в статьи о байткоде написано что название пошло от one- byte opcode, и говорится что выполняется он в виртуальной машине. В русской же вики о v8 написано «машинный код», в статье о машинном коде говорится что он читается непосредственно микропроцессорами или микропрограммами, с микропроцессорами ясно, а вот в статье о микропрограммах мишет что ето прошивки. Тоесть машинный код с виртуальной машиной не связан. Виртуальная машина выполняет не машинный код а опкод (коды операций). Выходит в русской вики ошибка (про машинный код в v8), и вы, соответственно, тоже ошибаетесь.

Или ето я чтото напутал?
Хм… В вики об етом помалкивают. Извиняюсь.
В ассемблер. Который потом компилируется.
Спасибо, ваша статья наконец-то сподвигнула меня на более пристальное изучение nodeJS.
Оффтоп: почему на фото статей или книг про javascript часто изображается носорог? Это как-то связано с движком Rhino?
не знаю… на на книжках про js почему-то рисуют носорга… наверное O Reilly во всём виноват =)
> обладающей довольно уникальной на сегодняшний день особенностью, неблокирующим I/O
Erlang (BEAM), Haskell (GHC), Python (Twisted, gevent, eventlet, concurrence), Ruby (EventMachine).

Программирование с коллбэками это же не удобно, не понимаю чего все нашли такого особенного в этом node.js, разве что на сервере на javascript писать. А так — это просто Twisted на javascript. Попробуйте лучше использовать что-нибудь с корутинами, типа Erlang, Haskell или Python (greenlet+gevent/concurrence/eventlet).
>не понимаю чего все нашли такого особенного в этом node.js
А вы напишите на любом из:
>Erlang (BEAM), Haskell (GHC), Python (Twisted, gevent, eventlet, concurrence), Ruby (EventMachine).
пример из статьи с 2х секундной задержкой, чтобы 10 одновременных соединений оно обслуживало не 20 секунд, и поймёте.
У вас в примере с Tornado вызов time.sleep блокирует весь event-loop, именно поэтому и получается такая красивая цифра ы 20 секунд = 10 соединений * 2 секунды задержки. То есть во время задержки другие соединения не обслуживаются. Учите мат. часть.
Я прекрасно понимаю, но хочу сказать что сделать на питоне sleep без блокирации event loop довольно слоожно и код будет намного длиннее! и большинство программисто которые пишут на python косвенно говоря используют именно sleep, например при обращении к БД они тоже блокируют event loop, точно также! И на данный момент я не видел решений которые предоставляли возможность писать неблокирующий скрипты легко и непренуждённо, как это делает Node.
> сделать на питоне sleep без блокирации event loop довольно слоожно и код будет намного длиннее!
В tornado это IOLoop.add_timeout, в Twisted — reactor.callLater, в Haskell — Control.Concurrent.threadDelay, в Erlang — timer:sleep(), в gevent — gevent.sleep.

> И на данный момент я не видел решений которые предоставляли возможность писать неблокирующий скрипты легко и непренуждённо, как это делает Node.
Видимо плозо искали.
Согласитесь, что когда понадобится прочитать файл или обратиться к бд, в повседневной жизни скорее всего вы будите использовать блокирующую функцию… И далеко не для всего найдёте неблокирующие реализации… А Node поставил перед собой цель зделать абсолютно весь ввод вывод асинхронным, в стандартных библиотеках, за что и заслуживает внимание уделённое в статье.
они переписывали все либы под это? Точнее, написали заново?

Если это без шуток, то следующий мой личный проектик будет на node :)
Да… причём все модули которые пишутся сторонними разработчиками тоже под это заточены…
у большинства общеупотребительных БД интерфейсы взаимодействия в корне синхронные — с этим не так просто что-то поделать.
Какие именно интерфейсы вы имете в виду?

Если соединение с сервером БД осуществляется через сокеты, то совершенно все равно, что с другой стороны используется неблокирующий сокет. Тут именно вопрос реализации клиента к БД.
угу… хотя к примеру libmysql синхронен по своей природе… поэтому до сих пор не сделали прямой коннектор для node… но есть dbslayer…
Есть drizzle, у него клиент асинхронный, и полностью совместим с mysql (так как drizzle — форк от mysql).
Twisted обращается к БД в отдельном потоке, то есть основной поток не блокируется. gevent/eventlet патчит модуль socket стандартной библиотеки Python и делает их неблокирующими, так что любая библиотека, которая использует python-сокеты автоматически становится неблокирующей. Последнее касается и драйверов БД.

Признайте уже, что облажались с примером на Python :-).
Но ведь Питон то тут не причём… я привёл пример на нём, так как мне нужно было на чёмто привести пример блокирующего приложения…
Но темнеменее 90% кода который я вижу на python — не асинхронный
откройте исходники любого шаблонизатора на python и убедитесь что он блокирующий… И Вам нужно будет постараться чтобы найти неблокирующий шаблонизатор, для node всё наоборот.
Шаблонизатор много у вас делает I/O? :) Не несите чушь :-).
Он читает файлы с шаблоном… в прочем действительно не удачный пример…
Тем не менее здорово когда платформа изначально заточена под асинхронность!
Штука интересная, потенциально аццкая, но вот проблема — под FreeBSD8 до сих пор не работает стабильно, периодически собираю новые версии и пробую хеловорд из коробки.
Да знакомая проблема… тоже жду пока поправят…
Недавно напарывался на JS-либу Concurrent.Thread, там же статья в PDF. Позволяет писать код примерно в таком стиле (пример из статьи):

 1: function load (url) {
 2:   var th = Thread.create(nowLoading);
 3:   try {
 4:     var res = Thread.Http.get(url);
 5:     document.write(res.responseText);
 6:   } catch (e) {
 7:     document.write("ERROR: " + e);
 8:   }
 9:   th.kill();
10: }
11:
12: function nowLoading () {
13:   var bar = ["|", "/", "-", "\"];
14:   var i = 0;
15:   while ( true ) {
16:     window.status = "Now loading..."
17:              + bar[i=(i+1)%4];
18:     Thread.sleep(125);
19:   }
20: }
21:
22: Thread.create(load, "http://...");


По сути дела они перепарсивают весь JS-код, регулярно вставляя вызовы менеджера задач — эдакая кооперативная многозадачность. Неимоверные тормоза на вычислительных задачах, но может пригодиться для Ajax-запросов, так как код действительно из лапши коллбэков превращается в нечто удобочитаемое.
а ничего, что time.sleep блокирующий в питоне?
так об этом то и речь! Писать на питоне неблокирующий код — не очень просто, а приведённый в статье пример и написан только для того чтобы показать разницу между блокирующим кодом и неблокирующим, обидеть питон здесь никто не хотел, я люблю питон!
дело в том, что примеры кода на js и питоне неравноценны. на питоне следовало сделать time.sleep в отдельном трэде, а так получилось что вы заставили питон и js делать разные вещи, а потом сравнили результат.
До меня по-моему дошло, что он пытается сказать — код не равноценный, но написание равноценного потребует больше усилий со стороны программера на питоне.
Потребуется меньше усилий, особенно при использовании библиотек с корутинами.
Ну для такого как он, да, много больше: )
Я в курсе, специально сделал это, я хотел показать разницу между блокирующим кодом и неблокирующим, я мог точно также написать второй пример на node используя команду блокировки wait, однако тогда мне былоты гораздо труднее объяснить что большинство на данный момент пишет именно блокирующий код… посмотрите на собственный код, например здесь запись в файл блокирует ваше приложение, а ведь в то время пока вы пишите в файл вы могли бы обслужить следующего пользователя…
неужели?
во-первых, outfile это не обязательно файл в явном виде, а объект с похожим интерфейсом, StringIO например.
во-вторых, запись в файл освобождает GIL и в этот момент начинают работать другие трэды. что-то народ с этой модой на асинхронность совсем голову потерял.
не, дружище, ты просто лоханулся с примером на питоне ) есть банальные правила для написания асинхронных приложений…
я знаком с Питоном, и знаю точно что правила далеко не банальные, особенно в вопросе работы с разными БД.
разные БД к асинхронности приложения прямого отношения не имеют
Обращение к БД и к ФС — два основных места где важна асинхронность, для event-loop приложений!
не только — любой ввод/вывод
Вы его просто не знаете. У вас каша в голове, милейший. Хотите полноценный sleep как в тут — сделайте на питоне в twisted reactor.callLater( чего там вам надо).
Или так, чтобы без колбеков, раз уж у вас пунктик. На генераторах, гринлеты тащить влом:
@defer.inlineCallbacks
def kukumsik():
      d = defer.Deferred()
      reactor.callLater(10,d.callback,"трямсики пришли")
      data = yield d
      print data


И больше не лезьте на минное поле без карты.
Не любитель торнадо, но там вроде есть tornado.ioloop.IOLoop.instance().add_timeout(цифирь, колбек)
Я не сомневался, но речь то не об этом, откройте любое ваше приложение где вы читаете из файла или делаете запрос к бд, и скажите честно блокирующие они у вас или нет! Конечно на питоне можно написать неблокирующий код, я не сомневался в этом, однако Питон не предоставляет стандартных инструментов для этого, и далеко не все инструменты которые это позволяют так элегантны как reactor.callLater, А давольно часто чтобы написать неблокирующий вызов приходится городить огород с тредами… а на node любой новичёк напишет быстрый неблокирующий код.
а трэды уже не модно использовать?
Вы точно прочитали статью?
>И я не сомневаюсь, что Питон программист быстренько перепишет мой пример используя threads, так, чтобы он работал как надо, вот только кода станет в 2 раза больше, да и потом поднимите руки те, кто каждый запрос к файловой системе или к базе данных оформляет в отдельный тред!
Слушайте, вы все никак не поймете — вы сделали грубейшую ошибку, из нее сделали идиотские выводы. Спрячьте пост и не позорьтесь.
Я сравнил блокирующее приложение с неблокирующим, и сделал обсолютно правильные выводы, Ваша проблема лишь в том, что вы не поняли о чём речь.
Я просто в теме, а вот вы явно не понимаете, что используете неблокирующий tornado, а пользуетесь при этом синхронной функцией. И я подозреваю, что просто подтасовываете результаты, уж больно упираетесь на очевидное. Впрочем ваш уровень владения темой ясен.

Хотите подобия честного теста — запустите приложение синхронное с потоками, не трогая торнадо, именно так оно и работает в реальном мире. А лучше — скрыть пост и не позориться: )
Боже!!! Я не сравнивал Tornado и Node… Вам лиж бы холивар завести… Я сравнивал Блокирующий ввод вывод с неблокирующим!!! Для того чтобы читатель понял зачем нужен nonblocking I/O… Кстати честный тест я тоже проводил, и победил Node правда с довольно скромным отрывом… за счёт того что v8, быстрее чем Питон, а также за счёт использования libev а не libevent внутри node.
Не трогайте, он занят, энтропия знаете ли, готовит нам новое уютное гнездышко. А мы тем временем вернемся к вашему тексту, и выведем из него прямые слова — лучшая библиотека на питоне tornado. «Лучшая для чего?» — воскликнет внимательный читатель, ведь он то в курсе, что торнадо и node.js аналоги. Все в курсе, кроме автора этого странного топика, который упирается всеми ороговевшими частями тела, не желая убрать это позорище и прямую подтасовку фактов.
Вы в проекте с гравицапой участия, часом, не принимали? Спешите, вас там ждут!

Выложите честные тесты, как минимум. Только сделайте так — ab -n 10000 -c 300, а то тут даже поперхнуться нечем, на 10 клиентах.
Ок… Ну давайте померяемся:
Значит tornado:
Time taken for tests: 70.054 seconds

А nodeJS:
Time taken for tests: 69.963 seconds
А теперь без задержек (Просто вэб сервер который отвечает hello world):
Tornado
Time taken for tests: 3.123 seconds

NodeJS
Time taken for tests: 1.931 seconds
может вы таки исходники нормально выложите?
не надо волноваться, я просто прошлый комментарий проворонил. )
Вот, отлично! А теперь вот это же в топик: ) Ну а рядом можете оставить с обычным sleep, вот тогда будет честно, и статья будет корректна.
Только там ab более детальную картинку отдает, просто время это не совсем показатель, добавьте rps еще.
А результат вполне ожидаемый, да, в два раза обычно и получается на CPython. Посмотрим что принесет нам ласточка, может и выйдет несколько подсократить разрыв.

А вариант со sleep надо запустить под многопоточным сервером, apache там к примеру — чтобы уж совсем к реальному миру приблизиться. Ведь мы понимаем, что когда работает блокирующий код, на http-сервере запускаются несколько экземпляров скрипта. И вот тут время общее выполнения сократится, а rps нам покажет некоторое преимущество неблокирующего подхода.
в питоне нужно написать:
tornado.ioloop.IOLoop.instance().add_timeout(time.time() + 2, self.async_callback(self.send_response)), а не setTimeout
+ нужно добавить декоратор: @tornado.web.asynchronous
и импортировать модуль «tornado.web»
а в node всё из коробки, и не нужно пол часа гуглить как это сделать
Не в python, а в tornado: ) У python есть еще десяток неблокирующих библиотек с stackless или гринлетами, и еще есть twisted, но вам я его даже предлагать не буду, чтобы предотвратить шок: )
И да, о ужас, иногда надо читать документацию. На node вы наверное не читали, озарение снизошло, что есть такая функция, как setTimeout?
имхо в tornado всётаки это реализовано сложнее
а используя swirl c tornado получается чуть ли не красивее, чем в node:

@swirl.asynchronous
def get(self):
yield lambda cb: ioloop.instance().add_timeout(time.time() + 2, cb)
self.write(«Hello World»)

см. pastie.org/820612

с этим туго сейчас к сожалению… Есть только один модуль… Ну и сам v8 неплохо информацию об ошибках формирует
Наверное, это будет оффтопом…
Но раз пошла такая пьянка со спором, где проще делать асинхронный ввод вывод и задержку, то позвольте представить вам пример из веб-сервера Misultin, написанном на Erlang.
Вообще, это эмуляция потоковой отгрузки данных, и она делает 3 раза задержку, но идея видна очень хорошо.

По-моему, трудно придумать что-то более простое и легкочитаемое.

-module(misultin_stream).
-export([start/1, stop/0]).

% start misultin http server
start(Port) ->
    misultin:start_link([{port, Port}, {loop, fun(Req) -> handle_http(Req) end}]).

% stop misultin
stop() ->
    misultin:stop().

% callback on request received
handle_http(Req) ->
    % send headers
    Req:stream(head, [{"Content-Type", "text/plain"}]),
    % send stream
    Req:stream("1"),
    timer:sleep(2000),
    % send stream
    Req:stream("2"),
     timer:sleep(2000),
     % send stream
     Req:stream("3"),
     % close socket
     Req:stream(close).
а чем лучше питонячьих-то вариантов? туды-сюды, порт, запрос, ответ, сервер…
Сделать вариант читабельным вообще не вопрос, все тот же twisted, tx_green мой:

from tx_green import make_it_green, wait

def sleep(t):
d = defer.Deferred()
reactor.callLater(t, d.callback,None)
return wait(d)

@make_it_green
def handler(request):
request.write(«heyho!»)
sleep(20)
request.write("!?")
sleep(600)
request.write(«Ищщо тут??»)
request.finish()
make_it_green — эт что значит? «зеленый» трэд? :)
greenlets… Понятно.

А вам не кажется, что лучше бы декоратор просто назвать «green»? Как-то в три слова такую простую вещь писать… oververbose
Sign up to leave a comment.

Articles