Автор Тема: Многопоточность и раздельные объектные пространства  (Прочитано 9561 раз)

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
По мотивам http://forum.oberoncore.ru/viewtopic.php?p=63851#p63851
Итак, имеем:
  • Единое адресное пространство и много потоков в терминах ОС.
  • Допиленный ББ (или другой ЯП) в котором каждый поток может иметь доступ только к своим объектам - объекатм, которые он сам создал и который он сам освободит.
  • Взаимодействие между потоками осуществляется только через сообщения (сериализуемые объекты).
Очевидные достоинства такого подхода:
  • Отсутствие race conditions для разделяемых данных (потому что их нет, хе-хе).
  • Сильно упрощается сборка мусора.
  • Больше поводов правильно инкапсулировать компоненты :)
  • А вот дедлоки все равно остаются :)

Как я понимаю, такая схема хорошо работает для случаев а-ля "один поток попросил что-то сделать, другой поток сделал". Хотелось бы комментариев от людей, которые щупали это на практике, применительно к другим случаям:
1. Насколько эффективно такой подход работает для случаев, когда один поток что-то делает и имеет обновляемый статус/данные, а куча других потоков читает этот статус/данные. По сравннию с классическими локами на запись/чтение.
2. Как передавать большие объемы данных между потоками. Вопрос прежде всего к Илье и его ББ, потому как в других языках (эрланг - пусть Алексей Веселовский подтвердит) такая проблема нивелируется иммутабельностью данных.

valexey

  • Administrator
  • Hero Member
  • *****
  • Сообщений: 1990
    • Просмотр профиля
Иммутабельность важна в данном аспекте только для сообщений. Тогда все хорошо. Причем поскольку у нас сообщение, по сути, вещь в себе (то есть не содержит ссылок, то есть просто шмат памяти), то его можно не собирать сборщиком мусора, а достаточно простого подсчета ссылок. Тогда если у нас прут большие массивы данных из одного потока многим, не нужно дублировать сообщение каждому получателю, достаточно дать каждому из них ссылку на данное сообщение, которое помрет тогда, когда о нем все забудут.

Собственно такая стратегия используется в erlang'e для больших бинарей в сообщениях.

Гм. Выходит что область памяти для сообщений должна быть за пределами областей памяти каждого из процессов (коль мы говорим о полном разделении областей памяти, я буду употреблять термин процесс а не поток). Отправляющий говорит - вот это сообщение отправь вот этим вот. Оно копируется в системный пул сообщений, затем всем остальным раздаются на него указатели. Само сообщение остается read only.

Из минусов — имеем лишнее копирование данных (в обычном случае у нас будет 0 копирований). При этом локов действительно может и не быть вообще (lock free очереди никто не отменял). В общем, зависит от задачи на самом деле. В общем случае отношение производительности одного подхода к другому не определено.

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

PPS. Подозреваю, что мы изобретаем велосипед, и если взять какой-нибудь хрюникс на системе без MMU (а такие бывают, да), и взять какой-нибудь голимый pipe, или unix domain sockets, или другое IPC, то мы получим ровно то же самое.
"но сейчас, чтобы компенсировать растущую мощность компьютеров, программисты используют фреймворки"

valexey

  • Administrator
  • Hero Member
  • *****
  • Сообщений: 1990
    • Просмотр профиля
И да, дедлоки остаются, но становятся другими.
"но сейчас, чтобы компенсировать растущую мощность компьютеров, программисты используют фреймворки"

valexey

  • Administrator
  • Hero Member
  • *****
  • Сообщений: 1990
    • Просмотр профиля
Ну и я не говорю уже про то, что в Go, D2, erlang'e, haskell'e все это уже есть. Ой, все таки сказал  ;D
"но сейчас, чтобы компенсировать растущую мощность компьютеров, программисты используют фреймворки"

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Ну и я не говорю уже про то, что в Go, D2, erlang'e, haskell'e все это уже есть. Ой, все таки сказал  ;D

Еще больше конкретизирую: есть 100 процессов и они хотят прочитать состояние одного выделенного процесса A. Как это работает? Эти 100 процессов посылают сообщение "дай мне свое состояние" процессу А, затем ждут, пока процесс A ответит (пошлет каждому из 100 ответ "мое состояние вот такое")? Или я чего-то не так понимаю? Если так, то ИМХО, это будет очень сильно тормозить по сравнению с локами.

valexey

  • Administrator
  • Hero Member
  • *****
  • Сообщений: 1990
    • Просмотр профиля
Ну и я не говорю уже про то, что в Go, D2, erlang'e, haskell'e все это уже есть. Ой, все таки сказал  ;D

Еще больше конкретизирую: есть 100 процессов и они хотят прочитать состояние одного выделенного процесса A. Как это работает? Эти 100 процессов посылают сообщение "дай мне свое состояние" процессу А, затем ждут, пока процесс A ответит (пошлет каждому из 100 ответ "мое состояние вот такое")? Или я чего-то не так понимаю? Если так, то ИМХО, это будет очень сильно тормозить по сравнению с локами.

Скорее каждый из них пошлют ему один раз сообщение - хочу подписаться вот на такие то события (изменения вот этого вот состояния), и этот процесс будет им слать сообщение с дифом состояния каждый раз когда оно изменится. При некоторых реализациях мультикаста (как я показывал ранее) будет практически без разницы один подписался или 100 000.
"но сейчас, чтобы компенсировать растущую мощность компьютеров, программисты используют фреймворки"

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Скорее каждый из них пошлют ему один раз сообщение - хочу подписаться вот на такие то события (изменения вот этого вот состояния), и этот процесс будет им слать сообщение с дифом состояния каждый раз когда оно изменится. При некоторых реализациях мультикаста (как я показывал ранее) будет практически без разницы один подписался или 100 000.

Да, я примерно такое решение и представлял. Проблема с ним только одна - оно сильно более навороченное, чем лок :)

valexey

  • Administrator
  • Hero Member
  • *****
  • Сообщений: 1990
    • Просмотр профиля
Скорее каждый из них пошлют ему один раз сообщение - хочу подписаться вот на такие то события (изменения вот этого вот состояния), и этот процесс будет им слать сообщение с дифом состояния каждый раз когда оно изменится. При некоторых реализациях мультикаста (как я показывал ранее) будет практически без разницы один подписался или 100 000.

Да, я примерно такое решение и представлял. Проблема с ним только одна - оно сильно более навороченное, чем лок :)
В каком месте оно более навороченое? :-) Лок, знаешь ли тоже не простая штука, ты ведь наверняка знаешь как оно унутре устроено. Вот представь себе что этот самый лок (то есть мьютекс) тебе пришлось бы реализовывать каждый раз :-)

Вопрос в библиотеках в общем то и в засахаривании этого дела в синтаксе языка.

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

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
В каком месте оно более навороченое? :-) Лок, знаешь ли тоже не простая штука, ты ведь наверняка знаешь как оно унутре устроено. Вот представь себе что этот самый лок (то есть мьютекс) тебе пришлось бы реализовывать каждый раз :-)

Кстати, подсчет ссылок в многопоточной среде - тоже не бесплатный ;)

Вопрос в библиотеках в общем то и в засахаривании этого дела в синтаксе языка.

Вообще при разбивке на отдельные процессы получаем приятный побочный эффект в виде явно формализованых протоколов общения отдельных компонент.

C этим я согласен. Но тем не менее :)
int a = lock( shared_a ).a;

Превращается в:

another_thread.send( get_a_msg() );
int a = another_thread.wait_for_answer<set_a_msg>().a;

Плюс код, который отрабатывает получение get_a_msg и отправляет set_a_msg.
Можешь расписать такой пример на эрланге?