Вы читаете dmitry_vk

Вт, 3 апр, 2012, 23:36
ICFPC 2012 is coming

Не могу не сослаться на то, что ICFPC будет 13 июля.

Пн, 13 фев, 2012, 23:45
К слову о нитях и лапше

Что-то много очень адептов node.js и прочих «магических» технологий говорят о том, что «нити (threads) и блокирующие вызовы - suxx», а «лапша из колбэков и асинхронные вызовы - rulezzz».

TL;DR

  1. event-driven concurrency с колбэками эквивалентно thread-based concurrency
  2. можно реализовать нити (threads) с минимальным оверхедом
  3. нити дают возможность писать естественный, последовательный код
  4. поэтому threads >> events + callbacks

Немного теории.

И последовательный блокирующийся процесс вычисления, и асинхронный неблокирующийся процесс имеют определенное состояние. Например, для процесса обработки http-запроса состояние может содержать:

  • сокет и связанные с ним ресурса ядра
  • буфер для чтения из сокета в юзерспейсе
  • состояние http-парсера
  • заголовки http и тело запроса
  • состояние парсера тела запроса
  • буфер для ответа
  • внутренние данные функции, генерирующей ответ на запрос (например, буфер под результат запроса к БД)

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

Пропоненты некоторых модных технологий убедительно рассказывают о том, что единственный правильный способ написания «web-scale»-приложений - это отказ от нитей и блокирующихся вызовов и переход на написание программ в стиле «лапша из колбэков». «Лапша из колбэков» есть ни что иное, как код в continuation-passing style. Осуществить преобразование последовательного кода в CPS вручную - задача довольно механическая, трудоемкая и склонная к ошибкам.

К сожалению, сложилась ситуация, когда многие программисты не имеют базового образования в области Computer Science и имеют слабое представление о процессах вычисления (в отличие, например, от выпускников университетов, где преподают курсы вроде SICP). На самом же деле, CPS и последовательный код эквивалентны друг другу: цепочка колбэков - это стек вызовов, представленный в виде односвязного списка.

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

Практика.

Основной аргумент, высказываемый против thread-based concurrency - это то, что нити занимают много ресурсов и поэтому их нельзя много создать. Для нативных нитей это так и есть: у них есть относительно большой оверхед на создание, значительно потребление памяти (место тратится под стэк (обычно несколько мегабайтов), thread-local storage, информация для планировщике нитей в ядре) и значительный оверхед на переключение контекста. Но нити, предоставленные ОС - это только один из вариантов реализации нитей: их можно реализовать с меньшим оверхедом.

Разберем, например, нити в Linux + glibc. Итак, что включает в себя нить:

  • структуры данных в ядре ОС, которые содержат информацию для планировщика
  • стэк
  • сохраненные значения регистров CPU и FPU
  • маска сигналов нити
  • место под результат нити
  • объекты синхронизации

Основные накладные расходы при использовании таких нитей заключается в следующем:

  • переключение нитей всегда происходит из ядра ОС, т.е. всегда есть переход в userspace и обратно; а это губительно для производительности, если происходит много переключений
  • планировщик нитей, в зависимости от реализации, может начать тормозить из-за большого количества нитей
  • обычно у нитей достаточно большой стек, около нескольких Мб; из-за этого они занимают много памяти. Это основная причина, почему нельзя создать много нативных нитей

Первое, на что можно обратить внимание, это наличие в POSIX средств для переключения контекста - makecontext, getcontext, setcontext, swapcontext. Контекст в POSIX представляет собой все состояние нити за исключением объектов ядра и объектов синхронизации. С помощью таких контекстов можно довольно просто организовать нити. Такие нити, созданные в userspace, называются green threads. При этом, стэк для нити мы должны предоставить сами; это дает возможность управлять и минимизировать потребление памяти нитями.

Самый большой минус контекстов POSIX заключается в том, что контекст хранит также маску сигналов, и для ее переключения нужен системный вызов (чтобы обеспечить POSIX'ную семантику переключения контекста). Причем зачастую маска сигналов на самом деле и не нужна. Если реализовать swapcontext вручную (это займет несколько десяток строк кода на ассемблере для каждой поддерживаемой архитектуры), то накладные расходы сильно уменьшатся. Также можно не сохранять те регистры, которые не обязаны быть сохранены при вызове функции.

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

В итоге, использование green threads позволяет писать такой же простой последовательный код и запускать много нитей. Поэтому я выбираю green threads для задач, связанных с I/O; а для остальных задач - OS threads.

See also:

PS[0]. А node.js вместе при использовании node-fibers совсем даже неплох (если закрыть глаза и не видеть javascript). node-fibers использует libcoroutine для организации легковесных нитей в v8, что спасает от лапши из колбэков.

PS[1]. Erlang с его сотнями тысяч процессов - типичный пример успешного использования green threads.

Пн, 16 янв, 2012, 16:13
Job ad

Казанской компании 10tracks, в которой я сейчас работаю, нужны программисты:

  • javascript-программист для браузерного фронтенда
  • программист мобильных приложений
  • программист бэкенда (сейчас бэкенд на java, но все может поменяться)

Возможны различные варианты устройства (в том числе и студентам на part-time).

Подробности вакансий — в http://10tracks.ru/job/.

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

Ср, 2 фев, 2011, 09:09
Поиск майнтейнера для cl-gtk2

Я уже некоторое значительное время не пишу ничего на лиспе, и поэтому мои лисповые проекты остаются заброшенными. Среди них есть и cl-gtk2. Но я не хочу, чтобы cl-gtk2 перестал развиваться, т.к. думаю, что он полезен и нужен для лисп-сообщества.

Поэтому я ищу желающих взять на себя cl-gtk2. Со своей стороны обещаю всяческую поддержку в виде консультаций и помощи.

Вс, 19 дек, 2010, 23:40
sbcl-1.0.45-windows-threads

Смержил патч от akovalenko, использующий TLS-слот 63. С ним и возникла проблема — каким-то образом забыл смержить следующий его коммит, исправляющий опечатку; из-за этого (и из-за нехватки времени) не мог понять, в чем дело. Вообще, надо быть внимательнее и не допускать таких оплошностей.

После чего уже смержил SBCL-1.0.45 и выложил сборку (содержащую часть патчей от akovalenko) на https://sites.google.com/site/dmitryvksite/sbcl-distr/sbcl-1.0.45-threads.msi.

Пт, 17 дек, 2010, 00:02
update

Опять вынужден заниматься отладкой SBCL - после мержа версии sbcl и akovalenko в sbcl-windows-threads стали появляться странные ошибки доступа к памяти. Но после разборок с ними надо будет заканчивать с нитями и отправлять в SBCL.

Вс, 21 ноя, 2010, 09:20
Еще о FS:0x14

Apache Harmony JVM под виндой также использует поле Arbitrary Data в TIB для хранения указателя на TLS (пруфлинк).

А еще это поле используется для хранения TLS в библиотеке GML (OpenGL Multithreading Library) внутри проекта Spring (Spring - это игровой движок для запуска игр вроде Total Annihilation).

Вт, 16 ноя, 2010, 10:32

Встретил в блог-посте ссылку на статью «One-pass Code Generation in V8» (хотя это скорее набор слайдов к докладу, но буду так называть). Статья мне очень понравилась, как по содержанию, так и по стилю подачи материала. В ней описывается архитектура кодогенератора, которая содержит несколько техник, которые позволяют генерировать код без «глупостей» вроде "push eax; pop eax;" без применения peephole-оптимизатора, а за счет предоставления большей информации для процедур генерации примитивных операций.

На первый взгляд, довольно похоже на архитектуру кодогенерации в SBCL.

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

Пн, 15 ноя, 2010, 06:45
cl-sqlite-0.2

Выложил новую версию cl-sqlite-0.2.

Добавилась поддержка именованных параметров в запросах. Для сигнализирования ошибок используется тип sqlite-error вместо cl:error.

Ссылка на скачивание: http://common-lisp.net/project/cl-sqlite/releases/cl-sqlite-0.2.tar.gz.

Сб, 6 ноя, 2010, 23:39
sbcl-1.0.44-windows-threads

Обновил sbcl-windows-threads до SBCL-1.0.44, инсталлятор выложил на https://sites.google.com/site/dmitryvksite/sbcl-distr/sbcl-1.0.44-threads-1.msi.

10 most recent