Crossroad I/O был попыткой сделать улучшенный ZeroMQ, но не вышло и проект заброшен (https://github.com/crossroads-io/libxs последний коммит почти год назад). Как верно сказали дальше — сейчас активно развивается nanomsg в котором решили многие из существенных проблем ZeroMQ. мы сейчас как раз переводим часть системы от ZMQ на nanomsg именно из-за этих сложностей. Выглядит очень мощно, хотя некоторые из фич zmq там нет.
Однак и хоронить ZMQ рано — активно развивается, хоть и без Мартина, уже и 4 стабильная и пилится дальше.
Да. В нем хорошо реализован apple http streaming (mpegts), хоть автор дизайн протокола и ругает
Если вводные такие — видео сайт должен отдавать во flash, iOS, android, то мы пробовали делать, например, так:
кодируем
High profile H264 — 3 качества (X1.mp4 X2.mp4 X3.mp4)
Baseline H.264 — 2 качества (X4.mp4 X5.mp4)
под flash — отдаем OpenHttpStreamer'ом X1.mp4 X2.mp4 X3.mp4
под iphone — ErlyVideo X4.mp4 X5.mp4
под iPad — ErlyVideo X1.mp4 X2.mp4 X3.mp4 (там мощный чип декодирования и экран большой)
под android phone — http progressive download c ручным переключением X4.mp4 X5.mp4
под android pad — http progressive download c ручным переключением X1.mp4 X2.mp4 X3.mp4
Под android я не нашел информации про multibitrate dynamic streaming, поэтому пока только «ручками», как в m.youtube.com
Можно попробовать разобраться, что где происходит.
В django ORM явные кандидаты на тормоза — постоянные копирования QuerySet (которые нужны для модной ленивости запросов) + сигналы post_init для полей (которые нужны для модных полей вроде ImageField или GFK — но платят за это все, если в проекте хоть где-то есть хоть одна модель с ImageField или GFK) + генератор SQL на объектах (что нужно для поддержки всех баз данных и сложных запросов).
Что происходит:
1) qs = User.objects.all()
Метод .all() создает экземпляр QuerySet. QuerySet создает экземпляр Query. Экземпляр Query — достаточно большой питоний объект, у него где-то 50 полей (словарей, tuple, экземпляров других классов), создающихся в конструкторе.
2) qs[0]
При слайсинге сначала создается новый QuerySet (копируется исходный — в.т.ч. все из Query); у query выставляются новые лимиты: от [0, 1).
Затем по Query (который к базе не привязан) db.mysql.compiler.SQLCompiler собирает запрос для mysql (там всяческа логика на основе тех 50 полей из query).
Т.е. в тесте построение запроса и копирование QuerySet за цикл, можно сказать, не вынесено.
После этого запрос выполняется и для полученного результата строится экземпляр джанго-модели User, в процессе чего шлются сигналы pre_init и post_init. Если в проекте где-то используются ImageField или GFK (например, django.contrib.auth GFK используется), то у этих сигналов есть слушатели, «короткий» путь не работает, и при каждой отправке сигнала для всех слушателей проверяется, живы ли weakref-ы и тот ли sender.
.values() вдобавок к .all() убирает издержки по созданию экземпляра User (кстати, лучше просто написать было User.objects.values('username')). Для чистоты эксперимента можно еще User.objects.values_list('username', flat=True) попробовать, чтоб убрать влияние получения лишних данных.
Что где конкретно тормозит — профайлер покажет)
Но можно немного и без профайлера порассуждать. Т.к. values() вместо all() убирает издержки по созданию экземпляров User, то тормозит, наверное, постоянное копирование QuerySet и/или сбор Query в конкретный запрос под mysql.
Можно попробовать провернуть какой-нибудь хак и убрать копирование QuerySet/Query, чтоб проверить, тормозит это копирование или построение sql-запроса для бэкенда (код не проверял!):
qs = User.objects.values_list('username', flat=True)
qs.query.set_limits(0, 1) # получаем элементы из полудиапазона [0; 1)
for i in range(10000):
user = list(qs.iterator())[0] # iterator нужен, чтоб значения из кэша не брались
Если провести другой тест, в котором будет получаться 10000 результатов из одного запроса, проверяться будет скорость построения джанго-моделей (там values/values_list должен здорово помочь), т.к. sql строиться 1 раз должен будет.
Но точный ответ, понятное дело, только профайлер даст — узкое место всегда оказывается не там, где думаешь :)
От себя могу добавить, что при работе SVN 1.4 крайне не рекомендую изменять структуру репозитория в ветках. В первую очередь, не стоит выполнять перемещение файлов. Необходимость в этом возникает, например, при изменении структуры java namespaces в проекте (да, бывает и такое).
В перемещенные файлы невозможно корректно смержить изменения из, например, trunk'а или других веток. Так же, большие проблемы возникают при back-merge ветви в trunk проекта.
Можно не заморачиваться с лишними операциями, просто в атрибутах верхнего слоя (правый глаз) отключается красный канал:
Затем настраивается глюбина резкости, т.е. слои сдвигаются по горизонтали таким образом, чтобы самый близкий объект на двух слоях накладывался друг на друга, это точка 0. Если нулевую точку выстроить по-середине, то ближняя часть мотива «вылезет» из экрана, смотрите:
Ну и если совсем грамотно делать, то расстояние между левой и правой картинкой (по-умолчанию расстояние между глазами) должно равняться 1/30 от расстояния до главного объекта. Это важно. Снимая мелкие объекты стоит сдвигать фотокамеру на пару-тройку сантиметров, в то время как снимая городские джунгли можно смело сделать шаг в сторону. Вот тогда с глубиной будет все в порядке, и конечная фотка будет восприниматься глазами комфортно.
Отличный пост! В некоторых местах посмеялся от душа.
З.Ы. Египетские операторные скобочки ненавижу всей душой :)). Вспоминается комикс, где программист спрашивает у нового тимлида: «So, you are curly-bracket-on-the-same-line man or curly-bracket-on-the-next-line man»?
Всякий, кто будет лечиться в больнице ХХХ — дурак. Ведь средняя температура больных в этой больнице — 32 градуса. Статистика работает против вас — вы просто обречены на смерть. Как только вы начнёте там лечиться — по статистике вы уже остывающий труп.
По-моему, радио «Маяк» можно принимать даже на сосиску с кетчупом :) В самодельном приемнике с никудышной селективностью от него сложнее избавится, чем принять.
Если где-нибудь твориться беззаконие, полетит-ли из ваших рук HTC Hero помогать обделённым и притеснённым или надо будет ждать выхода следующей версии аппарата, Superhero? :-)
Однак и хоронить ZMQ рано — активно развивается, хоть и без Мартина, уже и 4 стабильная и пилится дальше.
Если вводные такие — видео сайт должен отдавать во flash, iOS, android, то мы пробовали делать, например, так:
кодируем
High profile H264 — 3 качества (X1.mp4 X2.mp4 X3.mp4)
Baseline H.264 — 2 качества (X4.mp4 X5.mp4)
под flash — отдаем OpenHttpStreamer'ом X1.mp4 X2.mp4 X3.mp4
под iphone — ErlyVideo X4.mp4 X5.mp4
под iPad — ErlyVideo X1.mp4 X2.mp4 X3.mp4 (там мощный чип декодирования и экран большой)
под android phone — http progressive download c ручным переключением X4.mp4 X5.mp4
под android pad — http progressive download c ручным переключением X1.mp4 X2.mp4 X3.mp4
Под android я не нашел информации про multibitrate dynamic streaming, поэтому пока только «ручками», как в m.youtube.com
В django ORM явные кандидаты на тормоза — постоянные копирования QuerySet (которые нужны для модной ленивости запросов) + сигналы post_init для полей (которые нужны для модных полей вроде ImageField или GFK — но платят за это все, если в проекте хоть где-то есть хоть одна модель с ImageField или GFK) + генератор SQL на объектах (что нужно для поддержки всех баз данных и сложных запросов).
Что происходит:
1) qs = User.objects.all()
Метод .all() создает экземпляр QuerySet. QuerySet создает экземпляр Query. Экземпляр Query — достаточно большой питоний объект, у него где-то 50 полей (словарей, tuple, экземпляров других классов), создающихся в конструкторе.
2) qs[0]
При слайсинге сначала создается новый QuerySet (копируется исходный — в.т.ч. все из Query); у query выставляются новые лимиты: от [0, 1).
Затем по Query (который к базе не привязан) db.mysql.compiler.SQLCompiler собирает запрос для mysql (там всяческа логика на основе тех 50 полей из query).
Т.е. в тесте построение запроса и копирование QuerySet за цикл, можно сказать, не вынесено.
После этого запрос выполняется и для полученного результата строится экземпляр джанго-модели User, в процессе чего шлются сигналы pre_init и post_init. Если в проекте где-то используются ImageField или GFK (например, django.contrib.auth GFK используется), то у этих сигналов есть слушатели, «короткий» путь не работает, и при каждой отправке сигнала для всех слушателей проверяется, живы ли weakref-ы и тот ли sender.
.values() вдобавок к .all() убирает издержки по созданию экземпляра User (кстати, лучше просто написать было User.objects.values('username')). Для чистоты эксперимента можно еще User.objects.values_list('username', flat=True) попробовать, чтоб убрать влияние получения лишних данных.
Что где конкретно тормозит — профайлер покажет)
Но можно немного и без профайлера порассуждать. Т.к. values() вместо all() убирает издержки по созданию экземпляров User, то тормозит, наверное, постоянное копирование QuerySet и/или сбор Query в конкретный запрос под mysql.
Можно попробовать провернуть какой-нибудь хак и убрать копирование QuerySet/Query, чтоб проверить, тормозит это копирование или построение sql-запроса для бэкенда (код не проверял!):
Если провести другой тест, в котором будет получаться 10000 результатов из одного запроса, проверяться будет скорость построения джанго-моделей (там values/values_list должен здорово помочь), т.к. sql строиться 1 раз должен будет.
Но точный ответ, понятное дело, только профайлер даст — узкое место всегда оказывается не там, где думаешь :)
От себя могу добавить, что при работе SVN 1.4 крайне не рекомендую изменять структуру репозитория в ветках. В первую очередь, не стоит выполнять перемещение файлов. Необходимость в этом возникает, например, при изменении структуры java namespaces в проекте (да, бывает и такое).
В перемещенные файлы невозможно корректно смержить изменения из, например, trunk'а или других веток. Так же, большие проблемы возникают при back-merge ветви в trunk проекта.
$ t(){ wget -qO- «ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=$1&langpair=$2|${3:-en}» | sed 's/.*«translatedText»:"\([^"]*\)".*}/\1\n/'; }
$ t «Что за нахуй» ru en
What a fuck
Enjoy!
Затем настраивается глюбина резкости, т.е. слои сдвигаются по горизонтали таким образом, чтобы самый близкий объект на двух слоях накладывался друг на друга, это точка 0. Если нулевую точку выстроить по-середине, то ближняя часть мотива «вылезет» из экрана, смотрите:
Ну и если совсем грамотно делать, то расстояние между левой и правой картинкой (по-умолчанию расстояние между глазами) должно равняться 1/30 от расстояния до главного объекта. Это важно. Снимая мелкие объекты стоит сдвигать фотокамеру на пару-тройку сантиметров, в то время как снимая городские джунгли можно смело сделать шаг в сторону. Вот тогда с глубиной будет все в порядке, и конечная фотка будет восприниматься глазами комфортно.
З.Ы. Египетские операторные скобочки ненавижу всей душой :)). Вспоминается комикс, где программист спрашивает у нового тимлида: «So, you are curly-bracket-on-the-same-line man or curly-bracket-on-the-next-line man»?
Хоть и не столь удобны, но незнающим людям с непривычки мозг выносят не слабо.