На днях Саймон Виллисон написал очень хороший пост про node.js. Саймону очень удаётся писать такие intro-посты про технологии, которые очень ясно передают самую суть вещей. Когда-то он так сподвиг меня взяться за изучение Джанго. Пост про node.js тоже хорошо даёт понять, почему это круто, и какое место в современной экосистеме веба он занимает. Кто ещё не слышал про node.js — начинайте читать с этого поста.

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

Node represents a clean slate. Twisted and EventMachine are hampered by the existence of a large number of blocking libraries for their respective languages.

Это, то почему я без восторга смотрю например на Tornado и на всякие задорные попытки запускать под ним ту же Джангу. Однако пост Саймона что-то вдруг повернул у меня в голове, и то, что раньше казалось мне проблемой, теперь кажется решением :-).

Впрочем, обо всём по порядку. (Осторожно, пост длинный!)

Две многозадачности

Мне известны всего два принципиально разных способа делать многозадачность.

Самый распространённый способ — исполнение кода в виде нескольких процессов или тредов. Неудивительно, что он появился самым первым и стал распространён: большую часть забот по распараллеливанию исполнения программы берёт на себя платформа — ОС или runtime языка. Программист же пишет код в знакомом с детства однопоточном синхронном стиле. Да, конечно есть проблемы с передачей данных между процессами, и проблемы с общими данным в тредах, но мы их как-то с грехом пополам научились решать. По крайней мере в не очень сложных случаях.

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

Проблема этого подхода — в производительности. Её, конечно, хватает сейчас почти на всё. Но начиная с какого-то момента многопроцессная система начинает кушать просто очень много памяти. Потому что, крути ни крути, эту память приходится копировать в каждый изолированный процесс (и copy-on-write до конца не спасает). Переключение на треды решает эту проблему, но снова не до конца. С ростом количества тредов система упирается теперь уже в резко возрастающее время простоя на локах, без которых синхронно в тредах программировать невозможно. Многим наверное знакомо типичное поведение веб-систем, запущенных в тредном режиме под нагрузкой: в какой-то момент она внезапно начинает сыпать 500-ми ошибками.

А хочется-то большего. Хочется десятков тысяч одновременных клиентов и тысяч RPS.

С такими нагрузками справляются системы, написанные в асинхронном стиле. Как только мы отдаём IO на откуп ОС и не блокируем свой процесс, у нас высвобождается куча времени: ведь очень много веб-приложений ничего очень долгого и умного не делают, кроме того, что плюют небольшой 20-килобайтный кусочек HTML'а в сокет. И этого "довольно много" на самом деле настолько много, что мы в состоянии обработать тысячи клиентов одним процессом, просто бегая по ним в цикле. И поэтому тривиальные "hello-world'ы" на Tornado уделывают любой многопроцессный сервер.

Проблема асинхронных систем

Но счастья нет и здесь. Проблемы начинаются, когда приложению нет-нет, да и приходится делать что-то сколько-нибудь долгое. Например получить из БД довольно большой и неудобный кусок данных и перегруппировать его императивными средствами. Или ужать картинку. Или обратиться сходить по URL'у на чужой сервер. Или отослать email. Или распарсить большой XML.

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

Обойти это можно, только если любые долгие операции как-то так переписать, чтобы они не блокировали выполнение основной задачи. Причём, как именно это делать, в общем-то, понятно. Можно уводить их в отдельные процессы-обработчики, можно использовать асинхронный IO — всё это уже опробовано. Но штука в том, что тот код, которым мы пользуемся сейчас — наши любимые библиотеки, которые парсят нам XML и отсылают письма, уже написаны в синхронном стиле.

Причём нам тут в вебе ещё повезло, у нас вся архитектура строится вокруг модели коротеньких ответов, и именно поэтому нам до сих пор удавалось держать десятки и сотни RPS с помощью традиционной многопроцессности. А вот если мы посмотрим, например, в сторону десктопного софта, мы увидим, что там похожая проблема стоит ещё острее. Какое-то время назад хардварные ребята показали нам фигу и сказали, что им поднадоело издеваться над кремнием в поисках там ещё бо́льших гигагерц, и единственное, что они могут нам предложить теперь — это 2 (или 4, или 32) параллельных ядра, и если мы хотим, чтобы наши программы работали быстрее, нам придётся придумать, как их использовать.

Однако десктопный мир полон софта, который написан в абсолютно синхронном стиле под один процессор. И от того, что мы запустим, скажем, две копии каталогизатора фотографий, они не прочитают содержимое флешки с фотками в два раза быстрее (сходите проверьте, если не верите).

Все эти наблюдения приводят к одному интересному выводу.

Если мы хотим, чтобы компьютеры работали значительно быстрее, нам придётся всё переписать в асинхронном стиле.

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

Вот вам прямо из головы задачка: асинхронный параллельный парсинг XML. Как мы сейчас парсим XML:

  1. Читаем данные из сокета. Как ни странно, это часть всей целиковой задачи по парсингу XML'а, просто по факту того, что в большинстве случаев собственно парсинг и приём случаются в одном и том же месте программы.
  2. Разбиваем входной поток на лексемы
  3. Обрабатываем их парсером.
  4. Строим дерево.

Жутко же неэффективно! Почему лексинг/парсинг уже полученного куска данных должен блокировать получение следующего куска? Почему бы лексинг разных кусков не делать в несколько потоков (map), которые потом объединять в единый парсинг (reduce), причём возможно тоже в несколько потоков? Зачем нам дерево, если в большинстве случаев пользователь всё равно будет на основе дерева составлять свои структуры — давайте придумаем удобную обработку элементов в SAX-стиле.

Всё это не так просто, но кажется очень интересным.

Язык

Я думаю, что большое значение имеет то, какой именно язык выбрать для глобального переписывания всего. Те объектные императивные языки, которыми мы с успехом пользуемся сейчас, кажется, не смогут выжить в новом мире, так же, как, например, C++ не стал мейнстримным языком веб-программирования, когда оно вылезло из коротких штанишек. Да, на Плюсах можно писать веб, никто не спорит. Но это просто неэффективно.

Мой любимый Питон по определению теряет здесь одно из своих больших преимуществ — большое количество написанных библиотек. Как раз потому, что именно их и надо все переписать. Зато его не сильно заметные сейчас недостатки — GIL и отсутствие полноценных анонимных блоков кода — магическим образом вырастают в размерах и вполне могут оказаться решающими.

Так чем тогда пользоваться? У меня в мыслях есть несколько кандидатов, каждый из которых имеет шансы стать Главным Языком Десятилетия. Какой выиграет, сказать не возьмусь, просто потому, что это зависит не только от качеств самих языков, но и просто от того, кому больше повезёт с хайпом, поддержкой и логотипом.

Пользуясь случаем, направляю вас заодно на цикл статей Concur.next, где Тим Брей обсуждает ту же языковую проблему существенно подробней. Собственно, я с ним согласен чуть менее, чем полностью, поэтому мысли мои здесь не оригинальны.

Haskell

Как многие говорят, функциональная природа языка — почти обязательное условие хорошей распараллеливаемости. Как только у вас есть неменяющиеся данные, вы, теоретически, избавляетесь от проблем с традиционным программированием с локами. Опять же теоретически, имея ленивые функции без сторонних эффектов, компилятор может в большой степени сам принимать решения о том, что и как можно параллелить. Я, впрочем, не большой знаток этого аспекта Haskell'а (да и остальных тоже :-)), поэтому могу тут здорово ошибаться.

В минусы языку записывается его большая сложность. Которая, в общем-то, убивает почти вся перспективу: если языком не можем пользоваться мы — туповатые инженеры — то писать и развивать библиотеки для реального мира становится некому.

Erlang

Как и Haskell, Erlang — язык функциональный. Но главное, там всё программирование происходит в терминах создания асинхронных процессов, и поэтому писать на нём асинхронные программы получается естественно.

Язык, однако, архаичен и странен. Кроме того, маленькое коммьюнити тоже не дают думать о том, что он когда-то прочно войдёт в мейнстрим. Впрочем, совсем помереть ему тоже не дадут, хотя бы потому, что CouchDB уже нужна всем, а написана как раз на Erlang.

GCD + Си с блоками

Apple придумала расширение к Си в виде анонимных блоков и сделала работающий общесистемный пул тредов — GCD. А это ключевые компоненты асинхронного программирования. Си — низкоуровневый язык, компилируемый в нативный код, который работает очень быстро. Да и поддержка Apple стоит многого.

Главный же минус Си в том же, в чём и плюс — он низкоуровневый. А также совсем не функциональный, и без автоматического управления памятью. Вполне может оказаться, что на Си с блоками будет программировать одновременно и долго, и сложно, и багоопасно.

Javascript

Удивлены? Я не случайно начал пост со ссылки на пост про node.js. Одна из мыслей Саймона в том, что Javascript совсем неплох, как язык для асинхронного программирования. Анонимные блоки кода там есть. Да и не отнять, что сейчас весь ajax пишется на Javascript именно в асинхронном стиле.

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

Clojure

И вот оно — моё любимое слово последней недели (кстати, по-русски я её как-то сразу стал называть "кложура" с ударением на последний слог). Про Clojure я узнал у того же Тима Брея. Потом пошёл на сайт, посмотрел на несколько выступлений Рича Хики об этом языке, и всё — по уши в него влюблён. (В язык, не в Рича :-) ).

Clojure — это Лисп. И для меня это плюс. Когда-то я лиспами заинтересовался, и стал тем, кого "скобочки не напрягают", мне очень нравится идея code-as-data. Хотя я понимаю, что это не для всех, но вы, ребята, сами виноваты :-).

Однако, уж если я вменил архаичность Erlang'у, то про Лиспы можно сказать то же самое, если не в большей степени. Но Clojure — это современный Лисп. Там есть не только списки, но и например нативные векторы и словари (задаваемые литерально фигурными скобками). Там нет проблем с юникодом (о чём чуть позже), и там много удобных макросов. То есть это Лисп, который придумали недавно, а не в конце пятидесятых.

Главная же фишка Clojure — это ориентация на многопоточность. Все структуры данных там неизменяемы (да, словари тоже), что даёт возможность распараллеливать доступ к ним вообще без локов. Эти неизменяемые структуры данных умеют очень дёшево дублироваться без использования полного копирования, что делает их быстрыми. И в языке есть несколько синтаксических конструкций, позволяющих явно задавать асинхронное выполнение и транзакции для связанных изменений. Всё это обязательно стоит послушать и посмотреть в оригинале в выступлении Рича Хики про параллельность. Оно длинное, но того стоит — взрывает мозг напрочь!

Хотя есть у Clojure и субъективный минус: она реализована на JVM. С одной стороны это очень практично: куча библиотек, готовая инфраструктура тредов, сборки мусора и JIT-компиляции. Очень правильный юникод, опять же. Но у меня ко всей этой инфраструктуре есть субъективная нелюбовь. Несмотря на то, что JVM уже много лет, она всё ещё вызывает проблемы при установке, всё ещё занимает немеряно ресурсов, и GUI-приложения на ней всё ещё не выглядят адекватно ни в одной десктопной среде (или я ошибаюсь?). Впрочем с практической стороны это всё не так страшно, если вести речь о веб-приложениях. Там все эти потроха пользователям не видны.

Так что официально заявляю, что в будущей гонке за процессорное время мой фаворит — Clojure.

P.S.

Забавно поворачивается история, однако. Когда-то, когда Windows 95 пришла на смену Windows 3.11, одним из главных преимуществ новой архитектуры было то, что вместо кооперативной многозадачности, когда каждое приложение должно было само давать работать другим, применялась вытесняющая многозадачность, когда время на процессы жёстко распределялось системой.

А теперь посмотрите, куда мы пришли. Выясняется, что внешняя система не в состоянии рулить своими процессами максимально эффективно, не зная их семантики. Хочешь независимого исполнения — делай копии всей памяти на каждый процесс, даже если каждому из них нужны лишь мизерные её доли. Жалко памяти — обвешивай доступ к любым системным объектам локами. И не получится оптимизировать раздачу времени процессам так, чтобы они по возможности использовали независимые ресурсы системы. Потому что для этого надо знать, что конкретно процессы собираются сейчас делать.

Поэтому мы снова возвращаемся к тому, что процессы сами должны управлять своим распараллеливанием. А это — та самая кооперативная многозадачность. Хотя, конечно, существенно более сложная и безопасная, чем в Windows 3.11, и с другими языковыми средствами. Но забавно :-).

Комментарии: 85 (feed)

  1. zw0rk.blogspot.com

    Очень хорошая заметка :)

    А в чем, по вашему, архаичность Эрланга?

    Я бы еще в плюсы кложуре записал то, что она может связываться с другими языками, крутящимися поверх JVM, особенно со Scala, который (имхо) тоже имеет большое будущее.

  2. elephantum

    К вопросу о Haskell - без дополнительных действий (явного указания/специальных структур данных) его нельзя параллелить, хотя бы потому что ленивость используется для бесконечных списков.

  3. elephantum

    Вообще асинхронность и тредность - это парадигмы, которые имеют разные области применимости.

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

    Асинхронность - много параллельных задач, задачи короткоживущие. Например, вебсервер. Задач меньше чем процессорного времени (иначе покупается еще один сервер), цель - увеличить эффективность использования процессора.

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

  4. Алексей Захлестин

    Ну, добро пожаловать в клуб :-)

    Я с clojure в ленивом режиме уже с пол-года вожусь. Очень хорошая вещь :)

  5. Виктор Коцеруба

    чтобы получить анонимные блоки в питоне надо совсем немного подхачить парсер

  6. otakuneko.ya.ru

    Выскажусь в пользу Эрланга (ну делал я на нём диплом, обожаю этот язык :)). Выше уже спросили: в чём, по-вашему, архаичность Эрланга? На мой взгляд это вполне современный язык с достаточным количеством библиотек и более-менее вменяемым Unicode в последних версиях. И обязательно нужно учитывать, что Эрланг это целая платформа OTP, а не только язык. Дело просто в том, что, программируя на Эрланге, следует думать совершенно иначе. Лямбда-исчисление это в первую очередь логичная и аккуратная математика, которую перенесли в высокоуровневый язык программирования. Эрланг очень прост, в нём нет много того лишнего, что есть в других языках (читай: императивных), от этого может показаться, что он беден возможностями и архаичен, но это не так. Вы же не говорите, что HTML архаичен, хотя в сущности он позволяет сделать только одну вещь: описать структуру документа. Эрланг в этом плане такой же. Он очень и очень прост и позволяет сделать только одно: описать желаемый результат. Причём в терминах абсолютной распараллеленности. На мой взгляд, если где и будущее — то именно здесь. Clojure может и крут, но JVM напрочь убивает все плюсы. Виртуальная машина Эрланга же чудовищно надёжна и позволяет делать горячую замену кода (причём даже нативных функций, написанных на С). Всё, чего там не хватает — классного веб-фреймворка а-ля Джанго. А веб-серверы на чистом Эрланге уже есть (целых два) и они показывают отличные результаты, JSON давно присутствует + Mnesia и CouchDB. Ну и возможность удобно и надёжно контролировать всю инфраструктуру.
    P.S. Ноги у Эрланга растут из Пролога, кстати. А ещё есть вполне рабочий и живой веб-проект на Эрланге: http://risovaska.ru/

  7. dp_wiz

    Всё, чего там не хватает — классного веб-фреймворка а-ля Джанго.

    1) Zotonic
    2) Chicago Boss

  8. Никита Васильев

    Javascript
    ... отсутствие стандартного способа сделать импорт библиотеки.

    http://narwhaljs.org/modules.html

    Этот способ конечно не build-in в самом JS, но сильно лучше чем ничего.

  9. Google user

    А мне нравится под eventlet писать в синхронном стиле, но IO под капотом асинхронное. В эрланге, хаскеле и node.js это "из коробки", без дополнительных библиотек.

    "Писать в асинхронном стиле" это уёбищный Twisted:

    get_url(foo_callback, foo_errback)
    
    def foo_callback(d):
      #process result, fetch another url
      return get_url(bar_callback, bar_errback)
    

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

    Кстати, в eventlet есть т.н. monkey-patching модуля socket. После этого традиционные синхронные либы на чистом питоне (например, urllib, myconnpy, pg8000) работают асинхронно. Да, либы с сишными ускорениями не пропатчишь на лету, увы.

  10. Google user

    Да, и самое главное, опять же упоминаемые Erlang и Haskell, а также Go, python-stackless, позволяют использовать именно потоки. "Традиционную" многозадачность. И всё нормально, нет проблемы 10к потоков. В двух последних есть проблема 10к connections. Она решается библиотеками.

    Если учесть, что это благодаря легким потокам и асинхронному IO в runtime библиотеке языка, будет повтор предыдущего тезиса:

    Возможно писать простой и понятный (потоки/процессы) код, который нормально работает с тысячами соединений.

    Для этого нужно две вещи: легкие потоки и асинхронное IO. И эти фичи обязательно должны быть совмещены друг с другом на уровне языка, может быть даже синтаксиса. python-stackless даёт одно, а Twisted другое. По отдельности - убожество. А в том же Erlang эти две фичи совмещены, на лицо удобство и радость разработчиков.

    P.S.: я не пропогандирую Erlang, мне тоже не нравится его архаичность, отсутствие документации, нормальных map(dict), record и, порой, стрёмные сообщения об ошибках.

  11. Yuri Baburov

    что ж, поздравляю, видимо, ты пропустил golang с его goroutines как ещё одно решение проблемы многопоточности.
    http://golang.org/doc/effective_go.html#concurrency

  12. Ivan Sagalaev

    видимо, ты пропустил golang с его goroutines

    Прости, а вариант "посмотрел и не понравилось" не рассматривается? :-).

  13. cybergrind

    А еще у эрланга есть rabbit-mq (реализация AMQP)
    И этот же AMQP очень помогает распараллеливать задачи используя питон. И есть Thrift. И тот факт, что люди меняют язык не очень охотно, скорее приведет к тому, что появятся библиотеки, помогающие распараллеливать программы намного проще, не меняя язык - надо под два ядра - запусти два питона. Просто может необходимость изучения новых "сложных" библиотек, приведет к росту доли "заточенных" языков.
    Хотя это так, абстрактное рассуждение, даже без особого обдумывания темы.

  14. bialix

    Что понимается под "clean slate" в фразе "Node represents a clean slate"?

  15. SaD

    А что думаете о языке F#?

  16. Google user

    Yuri Baburov, в Go просто лёгкие потоки. Как в Erlang, Haskell и python-stackless. Это позволяет моделировать задачи в стиле "на каждый чих по потоку". При наличии хорошего шедулера на реальные OS потоки, это позволяет очень эффективно использовать проц.

    Но это пол беды. Для эффективных приложений, которые в ожидании IO проводят больше времени, чем в вычислениях, ещё необходимо использовать асинхронный ввод-вывод; когда вы ждёте не каждый read/write, а сразу большую пачку и обрабатываете тот, который произойдёт раньше. Это позволяет эффективно использовать диск/сетевую карту.

    Одно автоматически не означает другое. Например, в python-stackless (если я не ошибаюсь) когда один тасклет начнёт писать в сеть, он заблочит все остальные. Лёгкие потоки есть, а асинхронного IO нет. В nginx, Twisted наоборот. По-моему, в этом Иван слегка ошибся. Кинул в одну кучу наезды на толстые OS потоки и на блокирующийся IO и сделал удобный вывод. А ведь это ортогональные вещи, если рассматривать их отдельно, предложенные выводы не столь очевидны и последовательны.

  17. coffeesnake

    Насчёт маленькой комьюнити Эрланга это Вы зря, последний год растёт как на дрожжах. Эрланг пиарят все кому не лень, начиная от упомянутой CouchDB и заканчивая 37signals, которые на нём Campfire написали. По популярности, размеру комьюнити и шумихе Erlang уж точно превосходит упомянутых Вами конкурентов (не считая JS конечно:)

    Очень задела фраза о том, что JVM - это недостаток :( да это просто "state of art" среди виртуальных машин с лучшим в мире GC.

    А питон надо поднимать, потому что нет другого языка, на котором было бы так приятно программировать. Надо срочно брать и писать свою реализацию Python 3k под V8 :)

  18. cybergrind
  19. Andrey Popp

    Сергей, полностью поддерживаю вас насчёт eventlet, правда я сейчас больше склоняюсь к gevent от Дениса Биленко.

    Иван, жаль, что вы не написали, каким образом в Clojure реализует конкурентное исполнение, как в этом ему помогает runtime и прочее.

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

    Кстати хочу заменить, что Erlang и Haskell (я имею ввиду GHC) впервую очередь отличаются и тем, что планировщики там не только коопертивные, но и вытесняющие. Это значит, что долгими вычислениями без I/O не остановить работу других в "потоках" — планировщик вытеснит текущий "поток" после n-го количества редукций в случае с Erlang или после n-ых тиков таймера в GHC.

  20. Hodzanassredin

    Для меня java в сравнении с dot net покрылась паутиной :-) А если по теме то F# имеет кучу интересностей в эту сторону типа неизменяемых даннх, асинхроных workflows, мailbox proccessor и т.п. Также для всех языков на дот нет есть Parralel extensions library позволяет декларативно использовать асинхронность. Ну и исследовательский проект от MS под названием Axum. Некоторые отмечают похожесть на Erlang но это немного другая концепция.

  21. Hodzanassredin

    Да в догонку Singularity как раз и демонстрировала потенциальную возможность написать все с нуля и продемонстрировать более эффективную асинхронность. Дешевые потоки и т.п.

  22. xonix

    Интересно, спасибо.
    Не увидел упоминания Stackless Python. Там тоже было уделено внимание легковесной многопоточности (greenlets). Когда последний раз смотрел, там даже были какие-то асинхронные обертки над сокетами и, возможно, I/O. Более основательно, по-моему, этими проблемами заняты товарищи из проекта PyPy.
    Да, в общем-то, эти возможности сейчас почти в любом новом ЯП есть - Scala actors, Google Go coroutines, ...

  23. Hodzanassredin

    Кстати о Haskell. В данный момент разработка этого языка спонсируется Microsoft так как автор трудится над ним в составе MS Research. И позиционируется в первую очередь как экспериментальный не для продакшн. А все продакшн реди фишки будут плавно перекочевывать опять таки в F#. Уфф извините за кучу сообщений, за живое задели :-) я умолкаю.

  24. Вегед

    Javascript
    ... отсутствие стандартного способа сделать импорт библиотеки.

    http://wiki.commonjs.org/wiki/CommonJS — хотя это пока только "начинание"

  25. Google user

    cybergrind, спасибо, теперь знаю официальную позицию stackless по этому поводу. Так вот, там буквально написано, что вот вам специальный костыль, делайте monkey-patching модуля socket и получите non-blocking IO. То есть в python-stackless поддержки async IO нет и есть средство для решения этой проблемы. А теперь попробуйте придумать причину по которой этот патчинг не делается автоматически и пользователям дают возможность наступить на грабли заблочив все тасклеты без патчинга socket.

    Ну и зачем тогда нужен отдельный интерпретатор, если ровно такой же подход работает с обычным CPython + eventlet? Скорость переключения потоков будет такая же, потому что eventlet использует greenlet - выжимку stackless. Сотни-тысячи сокетов eventlet (некоторые хабы) будет обрабатывать намного эффективнее, чем asyncore со своим select.

  26. Google user

    Hodzanassredin, лично по-моему, много полезных сообщений это хорошо, а MS-промывание-мозгов - плохо.

    Java не может сравниваться с .NET. Как ядро Linux с Windows Server. Как Firefox c libcurl. Если у вас есть аргументированное сравнение JVM с .NET CLR - вот это интересно.

    Некоторые отмечают похожесть [Axum] на Erlang но это немного другая концепция.

    Там тоже message-passing и актёры, но немного другой, да? Axum это Erlang с доступом к .NET библиотекам. Вот когда сделали C# - копию жабы, да, надо было отрекаться, потому что скопировали говно. Здесь не надо отрекаться. Хорошую вещь скопировали.

    В данный момент разработка этого языка [Haskell] спонсируется Microsoft так как автор трудится над ним в составе MS Research.

    А разработка Python спонсируется Google, т.к. Гвидо там работает, да? Это два разных факта; причинно-следственная связь, мягко говоря, натянута.

    P.S.: F# - действительно хорошая, полезная штука. Если C#-говнокодеры выучат immutability, message-passing и монады, может и правда, что-то хорошее выйдет.

    P.P.S.: всем остальным: извините, не удержался.

  27. Google user

    Иван, ещё, кстати, как-то в ЖЖ пролетала такая фраза, что раз в 10 лет надо переписывать заново весь стек: OS, библиотеки, сервисы, прикладные программы, опердень, всё. Тоже думаю, что это скорее не проблема, а решение.

  28. Ivan Sagalaev

    P.P.S.: всем остальным: извините, не удержался.

    Давайте всё же в конструктивных рамках оставаться.

  29. Yuri Baburov

    Прости, а вариант "посмотрел и не понравилось" не рассматривается? :-).

    Дык я о том, что тебе много чего не понравилось, но ты об этих альтернативах написал :)

  30. hodzanassredin

    А вчера сайт лежал что ли? Не мог зайти.
    to Сергей Шепелев да промывка мозгов это плохо. Каюсь. Но я дот нет разработчик, я аддиктед :-)
    1. Своей фразой про яву и паутину я хотел подчеркнуть свои устаревшие знания в области явы. Прошу прощение за некорректный Русский язык у меня была тройка.
    2. Axum это язык который вводит понятие доменов. В пределах домена это обычная работа с объектами в стиле ООП. Но границы домена можно преодолевать только с помощью каналов. Концепция каналов по словам разработчиков была взята ими из самой большой в мире распределённой системы Web :-) Я думаю нет смысла писать подробнее так как любой может пойти на википедию и прочитать более правильное описание.
    3. Действительно натянул как то не оттуда и не туда. Этим выражением я хотел подчеркнуть что мс заинтересованна в развитии Haskell и создатель языка тесно работает с ребятами из команды F#. Результаты совместной работы уже можно видеть сейчас например посмотрев на те же async workflows которые появились в f# благодаря влиянию Haskell. Так что можно надеяться что в будущем F# получит довольно интересные способности.
    Кстати Simon Peyton-Jones(создатель языка Haskell) совместно с Tim Harris(тоже получает бабло от MS :-) ) трудились над Software Transactional Memory платформой которая в скором времени будет интегрирована в dot net.
    Саймон иногда общается с Joe Armstrong вот кстати видео на эту тему http://www.infoq.com/interviews/armstrong-peyton-jones-erlang-haskell просто шикарные дядьки :-)
    Также можно взглянуть на:
    http://blogs.msdn.com/sos/archive/2009/07/23/Dmitri-Soshnikov-Interviews-Simon-Peyton-Jones-on-Functional-Programming-and-Haskell.aspx

    P.S. насчет быдло кодеров: такова участь многих c# программистов в том числе и меня, дрова надо рубить и наточить пилу некогда.

  31. Mike Ivanov

    Спасибо за статью. Кажется пришло наконец-то время Лиспа и Ко :-)

    Непонятно только почему Erlang назван архаичным.. Странный синтаксис - это да, но архаичность..? Эрланг - сравнительно молодой язык со вполне прозрачным и довольно внятным синтаксисом. Несколько запутаны правила пунктуации, но это не смертельно (особенно по сравнению с Python).

    Красота и мощь эрланговской модели не столько в асинхронности, а в том, что она позволяет прозрачно преодолевать сетевой барьер, то есть взаимодействовать с удаленными процессами, как с локальными. Clojure сосредотачивается на жонглировании агентами и отображением их на потоки => разные области специализации. Хотя Clojure'вская модель выглядит элегантнее.

    Что касается производительности, то до сих пор у Тима Брея ничего хорошего с Clojure так и не вышло - слишком много уходит на координацию и коммуникации, из чего можно сделать вполне банальный вывод, что не все задачи стоит распараллеливать. То есть, нужно чтобы сложность коммуникационной части была а) существенно ниже вычислительной и б) не росла квадратично с числом процессов. Парсинг XML в DOM к этой категории, увы, не относится.

    Совершенно согласен с тем, что JVM для Closure - это тяжкое бремя, а вовсе не преимущество. Сам язык - да, функциональный, но платформа - то есть библиотеки и VM - нет. Что делать с блокировками на уровне платформы - идей никаких нет. Будет ли Clojure жить если у него оторвать JVM - очень сомнительно, по крайней мере прецедентов таких не было.

    Поэтому мои ставки - на Erlang или на какой-то новый язык, но не Go, он слишком низкоуровневый. Возможно это действительно будет Javascript с подчищенным синтаксисом.

  32. Васисуалий

    Я тут слышал, что и Google и Yahoo подсаживаются (или уже подсели) на Erlang. По-крайней мере, в России, я точно знаю есть достаточно крупные проекты, где Erlang взят на вооружении, да на столько серъёзно, что в одном из них собрались спонсировать МГУ-шные курсы по Erlang-у.

    При таком раскладе вывод насчёт архаичности кажется скоропалительным.

  33. cdriper

    отсутствие полноценных анонимных блоков кода

    речь о лябде?
    дык чем описанная рядом функция от нее отличается?
    да ничем!
    и GIL не так страшен как его малюют.

    LISP явно не для средних умов, как тот же хаскель.

    Эти неизменяемые структуры данных умеют очень дёшево дублироваться без использования полного копирования, что делает их быстрыми

    а в чем хитрость? магия?
    кто мешает тебе такой же трюк сделать, например, на плюсах?

    и главное.
    по-моему, в статье спутано до кучи асинхронное (event-based) программирование и такая линейная запись алгоритма, которая при исполнении может быть автоматически раскинута на несколько ядер. это разные вещи.

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

  34. Imbolc
  35. Dmitry Vasiliev

    Текущая популярность языков:

    Haskell и Erlang - это не только названия языков, плюс, это совсем не популярность. :-)

  36. Deepwalker

    А по-моему вы все рано стали плясать на костях Python. Его чистый и простой синтаксис делает его очень перспективным.
    Не забываем про IronPython, Jython - ничто не мешает засунуть под капот любую другую реализацию.
    Обмен же сообщениями, асинхронность - это все легко делается. И Twisted не так страшен, каким кажется тем, кто его не до конца понял.

  37. zw0rk.blogspot.com

    LISP явно не для средних умов, как тот же хаскель.

    лисп простой. вот хаскелль да, требует определенной матподготовки.

  38. cybergrind

    stackless + stacklesssocket + epoll:
    http://osdir.com/ml/python.stackless/2008-04/msg00009.html

    в общем то написать любую свою либу для stackless + epoll - нет проблем (ну если вообще с неблокирующими сокетами имел дело).

    но в общем есть такая штука - асинхронность это еще не все. распараллеливаемость - тоже очень много. сейчас выпускают core i9 процессоры, в них 6 ядер. на серверах не редки случаи 8-16 ядер. сам по себе питон это богатство действительно неможет никак использовать, только танцы с бубном - у меня запущено хез сколько интерпретаторов, которые подключены к AMQP, но на больших нагрузках (20кк сообщений) система все равно висит. и оперативы все это дело съедает порядка гига (это только интерпретаторы). Но зато действительно параллельно и асинхронно (amqp через твистедовскую реализацию). В последнее время стал задумываться над тем, что даже простой перенос с питона на С принес намного большую производительность (микросекунды против миллисекунд). Пока перетягиваю куски на хаскель (одно конфигурирование под количество потоков добавлением +RTS +N4 - уже нечто), но дело пока туго идет =)

    p.s. предыдущий случайно раньше отправил, можно, пожалуйста, его удалить? и нету тут open id через gmail account?

  39. Сергей

    Кстати, какая сейчас в русском принята терминология, чтобы различать concurrent и parallel programming? Многозадачное программирование и параллельное программирование?

  40. Google user

    cybergrind, спасибо за аргументы. А на BSD надо будет обвзязывать на kqueue. Ту же самую задачу выполняет eventlet libev/libevent hub. Всё сводится к вкусу фломастеров. :)

    Кстати, питон может использовать ядра. threading даёт именно OS поток, которые скалируются на ядра. Я проверял и получал на двухядернике >100% в htop. Другое дело, что из-за низкой эффективности переключения питонских потоков и GIL накладные расходы настолько велики, что один поток нередко справляется лучше, чем два :)

    По поводу нагрузок под AMQP/Twisted предлагаю поразмыслить вот над чем: некто жаловался, что у них в нормальном коде (без багов) кончался лимит стека (1000). Увеличили до 2000, всё работает. Вот такой твистед. Но, конечно, с бешеным числом сообщений уже и сама медленность питонского интерпретатора может быть ботлнеком.

    Кнопки Google account нет, увы. Но вы можете ввести URL https://www.google.com/accounts/o8/id.

  41. Google user

    Думаю, что под архаичностью эрланга чаще всего подразумевается синтаксис пролога.

  42. Google user

    ну у меня recursion limit вообще никогда не исчерпывался, но, реализацию txAmqp я не люблю за @inlineCallbacks(ну ненравится мне как там реализовано все, особенно возврат значения через raise).
    а многопоточный питон делать смысла не имеет, разве что через multiprocessing. найденные ссылки на тему:

    http://backyardbamboo.blogspot.com/2009/02/python-multiprocessing-vs-threading.html

    http://stackoverflow.com/questions/1289813/python-multiprocessing-vs-threading-for-cpu-bound-work-on-windows-and-linux

    т.е. очень даже впечатляет, особенно по сравнению с простым тредингом. На той конторе, которой я сейчас работаю, большую нагрузку разрулили через coroutines + non blocking sockets(а еще написали самую быструю сериализациюдесериализацию из того что я видел для питона).
    но в общем то все решения - запуск большого количества интерпретаторов, незнаю как у кого, а у меня они получаются довольно тяжелыми и десяток-второй убивает пол-гига, а иногда и гигабайт оперативы, но это не страшно, учитывая сколько выжимается из этого дела. Но вот когда делаешь быстрые реализации, и видишь насколько они быстрее чем питоновские, начинаешь задумываться.

    А почитав материалы по поводу увеличения производительности, приходишь к выводу - достаточно писать асинхронные приложения, а распараллеливать уже на разные процессы - т.к. обычно такие распараллеливания очень хорошо горизонтально масштабируются (т.е. смог разнести на два процесса - можешь разнести на разные машины). В этом плане очень круто выглядит эрланг - который сам по себе может разносить задачи по разным машинам. Но, безусловно, срывает крышу обилие вариантов у хаскеля(до сих пор не понимаю, почему это не мэинстримовый язык, учитывая то, сколько там всего реализовано).

    сорри что как то сумбурно, почти час писал

  43. Google user

    Кстати елси не нравится Closure на JVM ведуться работы по портированию на CLR

    Посмотреть можно тут - http://github.com/richhickey/clojure-clr/

    Вики с описанием (хоть каким то) здесь - http://wiki.github.com/richhickey/clojure-clr

  44. bialix

    если сильно хочется померяться рейтингами популярности, то вот: http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html

  45. Nick Lutsiuk

    Повторю, что уже говорилось выше: в статье несколько спутаны две парадигмы - треды и асинхронность. А поиск подходящего языка нужно вести, определившись с нужной парадигмой. Для веба пророчат асинхронность - ОК, но чего тогда огород городить-то с GIL'ом?

    Что же касается "отсутствия полноценных анонимных блоков", то это очень непринципиальная проблема, которая имеет отношение разве что к читабельности (просто определяем неанонимный блок кода тут же, не отходя от кассы - пайтон это позволяет - и используем его). Проблема здесь кроется в другом. В отличие от Javascript, Python не имеет полноценных лексических переменных, что существенно ограничивает возможности callback-функций (по крайней мере, заставляет неочевидно извращаться с классами или генераторами). Хрестоматийный пример: http://www.paulgraham.com/accgen.html

  46. Google user

    cybergrind, я вот что подумал, внезапно. Надо собрать питон без поддержки тредов. Тогда в нём не будет GIL и процессы будут работать немного быстрее.

  47. Google user

    cybergrind, мы тоже всё делаем (хм.. ну я пытаюсь заставить) через coroutines + non-blocking sockets. Конкретно на eventlet, благо он всем понравился, а в 0.9 и баги пофиксили. Жаль только, что нет таких нагрузок, где б это действительно было нужно.

  48. Azazell

    лисп простой. вот хаскелль да, требует определенной матподготовки.

    Это не так.
    Хаскель сложен в основном из-за его системы типов. Монады - их часть. Но монады (как и большая часть остальных в нем вещей) - это не часть языка. На нем можно эффективно прогать, не зная про это все. Надо лишь понимать как работают конкретные вещи: Reader, State, Maybe.

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

    На самом деле, если не думать о сложностях и писать исходя из имеющихся примеров (мне лично хватило книги Real World Haskell), то довольно быстро набираешь необходимый практический базис, чтобы разбираться в системе типов. Плюс еще надо расширить своё понимание ООП.

    Я также как и вы думал пару лет назад. я его все это время время в фоновом режиме изучал... Но потом попалась книга RWH. И все стало просто.

  49. Денис Баженов

    Интересная заметка. И комментарии интересно читать.

    Одного вот только понять не могу. Зачем "переписывать все"? Я понимаю что асинхронная модель эффективна для IO. Но для CPU bound задач (например, тот же парсинг XML) полезность асинхронной модели под вопросов. Отталкиваться от этой модели при поиске удачных решений по распараллеливанию CPU bound задач не лучшая идея, на мой взгяд.

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

  50. Google user

    Денис, асинхронная модель при парсинге не используется, потому что IO не имеет отношения к парсингу :) сферический парсинг в вакууме предполагает, что у нас на входе непрерывный поток байтов с нулевой задержкой на чтение следущего байта. Иван правильно пишет, ждать окончания парсинга перед чтением следущего куска байтов бессмысленно, надо читать как только можно (пока памяти хватает), но это имеет отношение к вводу, а не к парсингу. Тут уже раза 3 делали вывод, что он в одном посыле смешал неблокирующееся IO и распараллеливание. Отсюда и конфуз.

  51. zw0rk.blogspot.com

    Я также как и вы думал пару лет назад. я его все это время время в фоновом режиме изучал...

    Я так думаю не просто так. Я не могу программировать, когда не знаю теоретическую базу под языком, что как и почему в нем сделано. Если с питоном тем же до таких вещей добираешься когда уже активно включился в работу (например, далеко не всем вообще нужно знать как конкретно работают del/new в питоне и т.п.), то с хаскеллем это сразу. И возникает естетсвенное желание понять что там да как. Мне было проще, я по профессии математик, но и мне все далось не сразу, учитывая то, что такие экзотические языки учат в фоновом режиме. Поэтому я и утверждаю, что хаскелль сложен для "человека с улицы". И уж он, очевидно, сложнее чем ЛИСП, потому что в лиспе нету ничего :) Там нечему быть сложным. Пара принципов и все по большому счету.

  52. xonix

    Проблема здесь кроется в другом. В отличие от Javascript, Python не имеет полноценных лексических переменных, что существенно ограничивает возможности

    Что-то Вы ошибаетесь:

    def foo(n):
      def q(i):
        return n + i
      return q
    
    def foo1(n):
      return lambda i: n + i
    
    print foo(5)(2) # => 7
    print foo1(5)(2) # => 7
    

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

  53. Ivan Sagalaev

    Тут уже раза 3 делали вывод, что он в одном посыле смешал неблокирующееся IO и распараллеливание. Отсюда и конфуз.

    Я ещё один пост скоро сделаю про этот момент. В этой области сейчас с терминологией, что русской, что английской, действительно хреново :-)

  54. Google user

    xonix, я, честно говоря, не понимаю, чем так плохи питонские лямбды (разве что экзепшон нельзя кинуть).

    Но вы схитрили. Там в правилах чётко написано, что нужно инкремент сделать, а не сложение. Для этого вам нужно будет сделать setattr объекту на который замкнута создаваемая лямбда. Как его получить - без понятия.

  55. Nick Lutsiuk

    Там в правилах чётко написано, что нужно инкремент сделать, а не сложение.

    Именно!

    Для этого вам нужно будет сделать setattr объекту на который замкнута создаваемая лямбда. Как его получить - без понятия.

    То, как решена задача по ссылке, я считаю - самый pythonic способ. Просто постановка задачи не способствует его нахождению. :) Повторю это решение здесь:

    class accgen_1():
        def __init__(self, n):
            self.n = n
        def __call__(self, i):
            self.n += i
            return self.n
    

    Если же делать с помощью замыканий:

    def accgen_2(n):
        def acc(i):
            acc.n += i
            return acc.n
        acc.n = n
        return acc
    
    def accgen_3(n):
        s = [n]
        def acc(i):
            s[0] += i
            return s[0]
        return acc
    

    Генератор тоже можно приспособить:

    def accgen_4(n):
        def incrementor():
            number = n
            while True:
                i = (yield number)
                if i is not None:
                    number += i
        acc = incrementor()
        acc.next()
        return acc.send
    

    Выглядит притянуто за уши, но помнится, где-то мне пригодилось замкнуть возвращаемую функцию на генератор (правда он был не бесконечный и чуть посложнее, чем здесь), так что пример не совсем лишен пищи для ума. И еще один, just for lulz (так бы пришлось делать, если бы не было метода send()):

    def accgen_5(n):
        def incrementor():
            number = n
            while True:
                number += 1
                yield number
        acc = incrementor()
        return lambda i: [acc.next() for x in range(i)][-1]
    

    Возможно, все это - оффтопик, но иллюстрирует мою точку зрения по поводу процесса создания функций (в т.ч. callback, которых в асинхронном коде придется писать много) "на лету" в пайтоне.

  56. entropyhacker

    Если смотреть глубже, то как насчет поменять и ОС в том числе, например, на Inferno?

    По теме, IMO, главая проблема не неэффективном многозадачном программировании, а в неэффективном программировании вообще. Любой проект рано или поздно достигает стадии, когда "надо все переписать" и эффективных решений этой проблемы пока не предложено. Все предложенные идеи (например здесь http://www.vpri.org/html/work/ifnct.htm)) пока не материализовались во что-то юзабельное. Поэтому сегодня все интересные проекты держатся на одной светлой голове и максимально возможном оттягивании 1.0 релиза, потому что потом backward-compatibility и смерть.

  57. Google user

    @Nick Lutsiuk

    по поводу процесса создания функций (в т.ч. callback, которых в асинхронном коде придется писать много) "на лету" в пайтоне.

    Что подкрепляет мой наезд на Twisted в частности и на призыв писать "код в асинхронном стиле" в целом:

    Не надо писать макароны колбеков. IO должно быть асинхронным, а код, его использующий - последовательным.

  58. Ivan Sagalaev

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

  59. david-m.livejournal.com

    Я ставлю на JS. Clojure — это, наверное, хорошо, но (эти (ваши (бесконечные скобочки))) и (слов (порядок (нечеловеческий (ваш этот))))… Проблема в том, что ни один из р-р-революционных ЯП не обладает человеческим синтаксисом, а значит, страшно далеки они от народа. Ну не нужны сейчас нафиг все эти ожившие мертвецы типа Лиспа… Вот ЗАЧЕМ там именно лисп? Если основной поинт — это неизменяемые структуры данных и транзакционная память — зачем это делать именно в этом древнем синтаксисе? Ну ещё бы Форт вспомнили, ей-богу.

    JS — отличный язык, крайне лаконичный и фантастически мощный, просто удивительно как такой шедевр могли сочинить в ответ на банальное ТЗ «сделать что-нибудь, чтобы в браузере картинки менялись». Node.js имеет в основе идею (отказ от синхронности), достаточно безумную, чтобы завладеть творческими массами:) Желаю ему всяческого успеха.

  60. Deepwalker

    Давид, вы пропустили один момент - ну зачем, зачем у JS эти страшные скобочки {}? По-моему синтаксис C не менее древний.

  61. Google user

    Иван, а что именно в питоне не для этого? Что предрасполагает к макаронам колбеков?

  62. yuppy99.ya.ru

    Заступлюсь за питон в целом и за twisted в частности. Мы очень давно пишем на twisted в асинхронном стиле и за все время код не был испорчен ни единым коллбэком. Этого удалось добиться с помощью генераторов питона 2.5. Вот простенький пример:

    from twisted.web.client import getPage
    
    @webtwist.deferred
    def getName(uid):
        xml = et.XML((yield getPage(GET_NAME_URL % uid)))
        yield xml.findtext('name')
    
    @webtwist.deferred
    def hello(request):
        request.write('Hello, %s' % (yield getName(request.auth.uid)))
    
    webtwist.bind('hello', hello)
    webtwist.run(8080)
    

    То есть оператор yield выполняет роль подождать окончания процесса для Deferred и роль return для простых значений. Нечто подобное позже сделали в inlineCallbacks, но там вместо yield во втором случае используется raise.

  63. david-m.livejournal.com

    YuppY: Вопрос от не-питониста: не является ли это своего рода хаком, затрудняющим понимание программы? Ведь yield, вроде бы, немного для другого предназначен?

  64. Ivan Sagalaev

    Сам yield предназначен для понятия "отдать управление назад, сохранив точку выполнения". Чаще всего он используется для итерации, но и такой способ применения вполне законен. И красив :-).

  65. Дмитрий Курилов

    YuppY, Вы сами написали @webtwist.deferred, или это какой-то "штатный" декоратор Twisted? И по какому принципу работает ожидание?

  66. Azazell

    Поэтому я и утверждаю, что хаскелль сложен для "человека с улицы". И уж он, очевидно, сложнее чем ЛИСП, потому что в лиспе нету ничего :) Там нечему быть сложным. Пара принципов и все по большому счету.

    Не-не... вы правы и хаскель действительно сложен.

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

    Сложность хаскеля - это фича. Его изучение дает понимание в смежных областях. Его понимание дает большие бенефиты в понимании "Сути вещей".

    Т. е. быдло-кодеры на хаскеле невозможны по определению и сути.

  67. Google user

    Дмитрий, смотрите реализацию inlineCallbacks (twisted.internet.defer)
    в двух словах, декоратор получает управление на yield'ах и заворачивает в deferred вызовы(надо чтото сделать асинхронно - ты просто делаешь yield того, что хочешь делать асинхронно). проблема скорее возникает когда ты хочешь чтото возвращать по выходу из функции - вот там это действительно некрасиво, все помним что нельзя использовать return в генераторах? в твистеде возврат значений сделали через raise.

    да и вообще, на мой взгляд, не совсем корректно говорить, что питон не создан что бы можно было писать каким-то определенным образом, просто некоторые вещи "под капотом" будут иметь сложную реализацию, но не более того (вы только посмотрите сколько охренительных вещей сделано на java. а ведь рядовой пользователь спринга может и не представляеть как оно работает внутри). если будет надо, ведь можно писать на си к питону, да хоть хаскель встроить =)

  68. yuppy99.ya.ru

    Давид, это не хак, про такой способ применения разработчики питона даже PEP написали: http://www.python.org/dev/peps/pep-0342/

    Дмитрий, webtwist.deferred мы написали сами, но inlineCallbacks от него по сути ничем не отличается. Если не нравится return через raise, то там достаточно подправить несколько строчек.

    Недостаток питона в отсутствии библиотек, способных работать асинхронно. Например, чтобы медленный запрос mysqldb не блокировал обслуживание других соединений, приходится выносить его в специальный пул тредов (twisted.internet.threads.deferToThread).

  69. holub
  70. Google user

    У YuppY в твистедном примере нет колбеков. Это отлично. И по-моему, это действительно пример "асинхронного стиля", потому что управление контроллируется программистом при помощи yield. Забыл написать yield - получил по башке дефередом.

    Предлагаю обсудить такой тезис: в чём вообще оправдание синхронного IO? Почему эти декораторы и yield надо явно писать? В eventlet/др. не надо. В raw-Python/Twisted можно, а в eventlet/др. нельзя написать явно блокирующийся IO вызов. Эта возможность прострелить себе ногу где-то нужна? Потому что я не вижу где бы это было полезно. Одни проблемы.

  71. Дмитрий Курилов

    Спасибо за ответы, хорошая пища для размышлений.

  72. Александр Сабуренков

    Да вот, кстати, http://code.google.com/p/coev/

    и не надо состязаться в написании колбеков наиболее читаемым способом.

  73. [...] Иван Сагалаев рассуждает о том, почему наступление многоядерных архитектур приведет к переписыванию существующего кода наново, Маниакальный Веблог » Надо всё переписать [...]

  74. Дмитрий

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

  75. Валерий Замараев

    Больше всего в twisted напрягает то, что с колбеками ты пишешь практически в continuation passing style. А на питоне это ой-как неудобно без лексического замыкания binding'ов (переменных). Поэтому очень хотелось чего-то подобного, реализованного в Common Lisp'е. Но javascript с нормальными замыканиями нам подходит :)

  76. Александр Чемерис

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

    Во-вторых, замечу, что блокировки - это не единственный способ синхронизации. Весь этот хайп вокруг lock-free не просто так поднялся. Да, сложно, но зачастую может прятаться вглубь библиотеки. А выигрыш даёт во многих случаях очень заметный. Кстати, насколько я знаю, JVM - одна из самых напичканых lock-free систем. Сановцы эту тему разрабатывают ещё с тех пор, когда компьютеры были большими.

    Про "проблему 500". Тут ещё может быть проблема с тем, что переключение процессов/потоков - это дорогая операция. И в идеальном мире на каждом ядре должен крутиться лишь один поток. При слишком большом количестве потоков lock contention и оверхэд переключений будет гасить все преимущества многопоточности. Ведь ядро-то одно, и в каждый момент всё равно выполняется только один поток.

  77. [...] шикарнейшая статья о производительности, распаралеливании задач и недалеких перспективах в программировании, написанная простым и понятным языком [...]

  78. Google user

    Александр Сабуренков, спасибо вам огромное за ссылку на coev. Очень интересный проект.

  79. [...] чем "всё переписать" надо рассказать людям - а что это вообще такое! Многие [...]

  80. Евгений

    По поводу программ как данных, что думаете о связке XML+XSLT+XQuery (последнее 2 можно автоматом генерить из тех же XML данных-деклараций). Все хранится и работает внутри Native XML СУБД eXist (http://exist-db.org)).

  81. magmoro.livejournal.com

    что значит отсутствие модульности в javascript? Про commonjs не в курсе (http://commonjs.org/)? Вот http://wiki.commonjs.org/wiki/Modules/1.0 описание модулей. В Node.js поддержка модулей реализована.

  82. Амир

    а как на счёт Lua ?

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

    можно ли об этом ЯП программирования говорить, что он позволяет писать программы работающие в многопоточном стиле ?

  83. Прошу прощения если кого задел вопросом, я не очень хорошо выражаю мысли.Я не много понимаю, что такое многозадачность, в чём проблема ассинхронности, и как работает многопоточная система, и хочу понять ещё лучше.Хочу понять - можно ли избежать очереди на обработку действий в самой джанго, и какие для этого используются решения. Как можно повысить производительность исполнения множества запросов, не банальным увеличением мощности ("ядерности") железа, и запуска большего количества потоков.Смысл был понять есть ли кто-то, кто пытается решать данный вопрос. Есть ли смысл пытаться решить его средствами джанго или питона. И есть сейчас решения которые уже можно пощупать.Раз уж здесь Иван Сагалаев, то почему питон не может быть языком используемым для написания в асинхронном стиле? Как вам кажется на сколько всё-таки перспективен язык Go в этом плане?И не надо про "ассинхронность I/O", это уже и так понятно ))

  84. Тенденция hardware-мира на сегодняшний день такова, что отказавшись от повышения тактовых частот все кинулись на многоядерность. О нормальном питоне здесь можно поплакать, потому что даже если вы идеально распаралеллите логику на потоки, один из них в любой момент времени блокирует весь процессор. Четыре там ядра или два. Слово для гугления — GIL (Global Interpreter Lock). В принципе, если потоки часто читают/пишут (на диск или в сеть) все терпимо ибо эти захваты происходят пока другие потоки ждут свои i/o. Но в принципе, похоже на приговор. И вот почему: помимо CPU можно заметить тенденцию интенсификации работы с GPU (cuda и пр.), где ядер изначально больше, но они не в сравнение проще CPUшных. Если хотите, это второй виток спирали: когда-то возникли математические сопроцессоры и в скором времени “втянулись” в CPU, теперь и директор по развитию бизнеса Intel в России утверждает , что графика войдет в центральный процессор, что техпроцесс опять уменьшится, и количество ядер возрастет до 40(!) уже в следущем году (ясно, не для простых смертных). И справедливо замечает, что в настоящее время “лагает” именно софт. Интересующимся еще посоветую статью Ивана Сагалаева “Надо все переписать”. Там же, в комментариях, было выражено мнение, что в скором будущем производительную мощность будут продавать как электроэнергию в наши дни, снабдив народ чем-то вроде нетбуков с очень широкой пропускной способностью сети. И по идее решение для “сервера-для-всех” напрашивается облачное, то, что мы сегодня видим на примере Amazon и гугла.

  85. Автор языка Clojure (см. статью Ивана Сагалаева) Rich Hickey рассказывает про свой процесс решения сложных проблем. Должно быть актуальным для всех, кто делает что-то новое. 3 вещи хочу особо отметить: background mind, книгу How to Solve It и "work on more than one thing, not interleaved within one day, but over the course of time".

Добавить комментарий

Format with markdown