LINUX.ORG.RU
ФорумTalks

Синхронные IPC vs Асинхронные IPC


0

0

Почти 8 часов утра, а значит пора ложиться спать. :) Но перед сном хотелось бы задать небольшую тему для обсуждения.

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

Почему? Используя асинхронные IPC:

во первых, появляется необходимость для хранения промежуточных данных. Это повышает накладные расходы;

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

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

p.s. Не стоит инвертировать мои аргументы.

p.p.s. Встретимся через 8 часов. :)

★★★

Ответ на: комментарий от tailgunner

> Эх... последний раз пытаюсь объяснить: речь идет о _времени реакции_, а не о частоте процессора. Чтобы тебе было понятнее: "громадный запас" по частоте процессора над частотой слышимых звуков имела уже PC/XT на 8086/4.88МГц.

Ну так проверь самостоятельно, если мне не веришь. Лишние пару сотен тактов, это катастрофа?

> Ну разве что это поколение разработаешь ты лично.

Дай денег, разработааю :)

Hint: первые процессоры с аппаратной поддержкой микроядерных IPC появились 20 лет назад. Примерно тогда же они исчезли.

Где об этом можно почитать?

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

Заметь, с этим утверждением я не спорю. Я спорю с заблуждением, что микроядра неэффективно решают эти задачи.

alman ★★★
() автор топика
Ответ на: комментарий от tailgunner

> Передавай привет знакомым эльфам.

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

tailgunner, стареешь, дружище. Раньше ты мог дольше спорить, оставая при этом корректным.

alman ★★★
() автор топика
Ответ на: комментарий от klalafuda

> все - или почти все - что вы описываете было успешно реализовано и использовано по всему миру в QNX4 ещё 15 лет назад ;)

Это хорошо. Кто скажет о QNX плохо - пусть первых бросит в себя камень. :)

alman ★★★
() автор топика
Ответ на: комментарий от fmj

> При такой разбивке задачи, в любом случае, мы получим некий предел Nmax, больше которого добавление новых ядер, уже не будет приносить никакого выйгрыша производительности. А тот-же linux, как говорят, вполне работает и на системах с 8192 процессорами, используя неблокирующие механизмы синхронизации, вроде RCU.

Думаю, в самом ядре не так уж и много задач, которые можно распараллелить более чем на несколько десятков процессоров. Тут вся скорость упирается в систему ввода/вывода. А что касается прикладных задач, то не вижу проблем. Если задачу можно распараллелить на 8192 процессоров, то особой разницы нет, микроядерное ядро или монолит.

> Похоже на агитацию за ФП ;) В принципе нечто общее тут есть, но драйвера часто портируют с других систем, а не переносят, так что преимущества у "традиционной" очень немалые.

Ну как-бы мне придётся согласиться. Хотя, портирование драйвера флопика из FreeDOS под L4 заняло около получаса. При этом выкинулся довольно сложный кусок с каллбэками на остановку мотора, а этот код реализован таймаутом на IPC. Получилось более красиво. Не сойти мне с места, если вру.

> Ну так вот, файловая система (много разных: FAT, extX, ZFS, xfs, и куча еще), сетевой стек, в том числе TCP протокол, у которого и так конечных автоматов хватает, стек драйверов устройств, собственно драйвера сложных устройств: сложных сервисов в системе каждый второй, так что умом поехать можно :)

Хе-хе. У меня есть FAT, ext2, minixfs, ISO9660, оригинальный devfs. Самое интересное - работает и даже параллельно при обращении нескольких процессов, не тормозит и не падает. Хотя времени, сил и здоровья на это ушло немало.

А на TCP/IP пока времени нет, но на пинги уже отвечает. Так что... ну может быть умом и поехал, но никому в этом не признаюсь. :)

Ничего, наступит день и на LOR появится новость.

alman ★★★
() автор топика
Ответ на: комментарий от anonymous

> Не, не больше. Ровно 100 дней :-) Я же сразу объяснил почему такая цифра взята, а во-вторых вы напрасно ёрничаете, если атомарная транзакция потребует столько времени - то вы хоть обперепроектируйтесь, а выполняться она будет ровно столько, сколько ей надо. Никогда не видели аналитических запросов в базу данных, которые по нескольку дней там живут, что-ли?

Вероятно, мне повезло. Таких запросов не видел. И что, при этом другие запросы останавливаются?

> Смысл использования IPC - это передача сообщений между процессами системы. И всё.

Однобоко смотришь. IPC - средство передачи сообщений между процессами и _нитями_, а также средство синхронизации.

> Только вот беда, что эти красивые синхронные процессы будут висеть 100 дней в ожидании ответа. Чем это лучше чем "висящие" сообщения?

Надеюсь, ты не будешь доказывать, что это хуже. Синхронные IPC хороши хотя бы тем, что их можно реализовать в железе. Чего нельзя сказать об асинхронных IPC.

alman ★★★
() автор топика
Ответ на: комментарий от tailgunner

> Когда спор идет на N-ый круг, это выматывает.

Да ладно, прошлый раз спорили более года назад. Много с тех пор воды утекло.

alman ★★★
() автор топика
Ответ на: комментарий от alman

> Думаю, в самом ядре не так уж и много задач, которые можно распараллелить более чем на несколько десятков процессоров. Тут вся скорость упирается в систему ввода/вывода. А что касается прикладных задач, то не вижу проблем. Если задачу можно распараллелить на 8192 процессоров, то особой разницы нет, микроядерное ядро или монолит.

Ну, тот-же TCP/IP, если есть достаточно толстый канал для интенсивного общения каждого ядра с внешним миром, то каждому ядру "будет что посчитать в режиме ядра" (хотя-бы чексуммы пакетов). Плюс в случае такого интенсивного использования сети, частые перебалансировки различных RB деревьев в ядре тоже будут поедать время.

К тому-же далеко не факт, что уже при увеличении числа ядер с 4 до 8-ми мы сможем как-либо алгоритмически распараллелить код: большую часть времени будет работать 1 поток, а сотальные 3/7 будут ждать результатов этого, уже более не делимого, потока. А ввод-вывод достаточный для обслуживания большиго числа ядер, чем 4 или 8 вполне в принципе возможен.

> Хе-хе. У меня есть FAT, ext2, minixfs, ISO9660, оригинальный devfs. Самое интересное - работает и даже параллельно при обращении нескольких процессов, не тормозит и не падает. Хотя времени, сил и здоровья на это ушло немало.

Ну вот и главный минус ;) Если в случае с ФП, мы наоборот экономим вермя разработки, то в данном случае мы его тратим больше, чем могли-бы :)

P.S. Вы лучше подумайте над разработкой формальной теории, для эквивалентного преобразования алгоритма в форму использующую синхронное IPC, продумайте DSL для написания сервисов, позволяющий с меньшими трудозатратами реализовывать подобные драйвера, напишите компилятор в C, и тогда от ваших идей будет может быть реальная польза ;) (Снова я на "вы" перепрыгнул, уже лень все менять, так что на последок немного общения на ты:) а пока практической пользы от твоих идей не так много, заинтересуют только фанатиков, кому времени не жалко своего ;)

fmj
()
Ответ на: комментарий от fmj

> Ну, тот-же TCP/IP, если есть достаточно толстый канал для интенсивного общения каждого ядра с внешним миром, то каждому ядру "будет что посчитать в режиме ядра" (хотя-бы чексуммы пакетов). Плюс в случае такого интенсивного использования сети, частые перебалансировки различных RB деревьев в ядре тоже будут поедать время.

ИМХО, эти задачи вполне решаемы и в контексте микроядерного подхода. Не вижу проблем диспетчеризации пакетов между свободными ядрами. А в случае перебалансировки RB деревьев, при классической реализации многозадачности, придётся создавать очередь блоков для записи на диск. Т.е. реализовывать синхронизацию вручную.

> К тому-же далеко не факт, что уже при увеличении числа ядер с 4 до 8-ми мы сможем как-либо алгоритмически распараллелить код: большую часть времени будет работать 1 поток, а сотальные 3/7 будут ждать результатов этого, уже более не делимого, потока. А ввод-вывод достаточный для обслуживания большиго числа ядер, чем 4 или 8 вполне в принципе возможен.

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

> Ну вот и главный минус ;) Если в случае с ФП, мы наоборот экономим вермя разработки, то в данном случае мы его тратим больше, чем могли-бы :)

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

> P.S. Вы лучше подумайте над разработкой формальной теории, для эквивалентного преобразования алгоритма в форму использующую синхронное IPC, продумайте DSL для написания сервисов, позволяющий с меньшими трудозатратами реализовывать подобные драйвера, напишите компилятор в C, и тогда от ваших идей будет может быть реальная польза ;)

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

alman ★★★
() автор топика
Ответ на: комментарий от alman

> Главное, чтобы никаких критических секций, которые на многопроцессрной/многоядерной машине ялвяются основной причиной нелинейного роста быстродействия.

Самое страшное, это не маленькие критические секции, обеспечивающие атомарность очень коротких операций, а RW-локи, из-за которых сотни потоков вынуждены ждать, пока 1 обновляет данные. Эту проблему замечательно решает RCU и при асинхронном IPC ;)

fmj
()
Ответ на: комментарий от fmj

> продумайте DSL для написания сервисов, позволяющий с меньшими трудозатратами реализовывать подобные драйвера

Occam скоро 30 лет

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

> Occam скоро 30 лет

Тут-бы что-нибудь более к C по синтаксису приближенное, да и крайне желательно найти набор абстракций более высокоуровневых, нежели простые потоки данных, и оперировать уже ими.

Но вернемся к исходной теме: что мы имеем на данный момент:

> Почему? Используя асинхронные IPC:

> во первых, появляется необходимость для хранения промежуточных данных. Это повышает накладные расходы;

Мы пришли к выводу, что накладные расходы в случае рализации сложных систем на подобном IPC так-же немалыми будут.

> во вторых, в случае обработки потоков данных, потребуется вручную реализовывать синхронизацию. Это лишние костыли;

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

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

"Отлично" масштабируемые при этом ;)

А помимо этого, используя синхронное IPC мы получаем:

* Просевшую латентность: время обработки запроса пропорционально количеству вложенных запросов, которые будут инициированы, при его обработке, для сложных запросов (вроде простого чтения блока файла), число вложенных запросов будет лавинообразно расти. Очевидно, что к обработке нашего запроса, запрашиваемый сервис приступит не мгновенно, аналогично и сервисы, которых будет запрашивать в свою очередь он, а в случае асинхронным взаимодействием, можно реализовать часть или даже всю обработку обобщенно говоря "в контексте вызова", т.е. если на нас нашли время, то нас уж обслужат сейчас, по край-не мере доведут запрос до отдачи в подсистему ввода/вывода, а там уже будут ждать результатов. Таким образом латентность sync-IPC системы можно оценить как O(N), где N-среднее число вложенных запросов инициируемых при запросе к тому или иному сервису, а латентность async-IPC, как O(1). И в том и в другом случае, не учитывается ввод-вывод, который понятное дело, занимает время, никак не связанное с алгоритмической сложностью той или иной схемы взаимодействия.

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

Усе, мне пора на работу выходить, больше я в этот топик писать не буду, по край-не мере до вечера.

fmj
()
Ответ на: комментарий от fmj

> Мы пришли к выводу, что накладные расходы в случае рализации сложных систем на подобном IPC так-же немалыми будут.

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

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

Естественно, использовать семафор и множество критических секций - большого экспиренса не надо.

> Просевшую латентность: время обработки запроса пропорционально количеству вложенных запросов, которые будут инициированы, при его обработке, для сложных запросов (вроде простого чтения блока файла), число вложенных запросов будет лавинообразно расти. Очевидно, что к обработке нашего запроса, запрашиваемый сервис приступит не мгновенно, аналогично и сервисы, которых будет запрашивать в свою очередь он, а в случае асинхронным взаимодействием, можно реализовать часть или даже всю обработку обобщенно говоря "в контексте вызова", т.е. если на нас нашли время, то нас уж обслужат сейчас, по край-не мере доведут запрос до отдачи в подсистему ввода/вывода, а там уже будут ждать результатов. Таким образом латентность sync-IPC системы можно оценить как O(N), где N-среднее число вложенных запросов инициируемых при запросе к тому или иному сервису, а латентность async-IPC, как O(1). И в том и в другом случае, не учитывается ввод-вывод, который понятное дело, занимает время, никак не связанное с алгоритмической сложностью той или иной схемы взаимодействия.

Перечитал несколько раз. :) Выглядит очень убедительно. Но не могу я так просто сдать идею. Итак. Для начала рассмотрим случай однопроцессорной машины. В этом случае мы получаем _управляемое переключение контекста_, т.е. sync-IPC является точкой, в которой система находит время для другой задачи. Иными словами, некоторый код отработает быстрее, если его исполнить два раза в одной нити, чем запустить этот код в двух параллельных нитях - поскольку переключение контекста занимает процессорное время. Естественно, речь идёт об однопроцессорной машине. Т.ч. ситуация с латентностью не настолько однозначна - проигрываем с латентностью, выигрываем в быстродействии. Рассудить нас могут только бенчмарки, полученные в результате теста, и десктопное приложение. :)

Теперь рассмотрим многопроцессорную/многоядерную машину. Здесь возражу только одно - ну не верю, что RCU это "серебрянная пуля". Да, использование этой технологии даёт значительные преимущества перед критическими секциями со spinlock, но использование sync-IPC позволяет вообще отказаться от критических секций. Т.ч. и здесь подождём бенчмарки.

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

Насчёт практической пользы - аргумент неоднозначный. Мои аргументы - минимизация переключения контекста и отказ от критических секций на уровне ядра.

alman ★★★
() автор топика
Ответ на: комментарий от fmj

>> Occam скоро 30 лет

> Тут-бы что-нибудь более к C по синтаксису приближенное, да и крайне желательно найти набор абстракций более высокоуровневых, нежели простые потоки данных

Лет 20 назад в Occam появились протоколы (в Occam2). Occam3 я уже не интересовался. Привинтить бы к этому pattern matching, и современный язык параллельного программирования готов.

tailgunner ★★★★★
()
Ответ на: комментарий от alman

> Здесь возражу только одно - ну не верю, что RCU это "серебрянная пуля".

Почему бы и нет? RCU избавляет потоки, занимающиеся только чтением, от каких-либо фактических блокировок (если не считать мироопераций окруженных спинлоками, которые можно считать для удобства, атомарными машинными инструкциями:).

> Насчёт практической пользы - аргумент неоднозначный. Мои аргументы - минимизация переключения контекста и отказ от критических секций на уровне ядра.

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

fmj
()
Ответ на: комментарий от fmj

Отвечу поближе к ночи.

Господа fmj и tailgunner, с вами интересно общаться - ваша критика по существу. Надеюсь, до ночи тема не уйдёт из видимости.

alman ★★★
() автор топика
Ответ на: комментарий от fmj

>> Здесь возражу только одно - ну не верю, что RCU это "серебрянная пуля".

> Почему бы и нет? RCU избавляет потоки, занимающиеся только чтением, от каких-либо фактических блокировок (если не считать мироопераций окруженных спинлоками, которые можно считать для удобства, атомарными машинными инструкциями:).

К сожалению, у меня большая иррациональная неприязнь к спин-локам. :) Слишком похожи они на пример, когда вместо ожидания прерывания, в цикле опрашивается порт.

> По поводу переключения контекста, -- не понял, мне кажется наоборот, переключений контекста будет больше, ввиду того, что запрос будет разбиватся на множество поздапросов, каждый будет обрабатыватся отдельным потоком (если конечно же речь не идет о SMP, с числом ядер большим чем число потоков задействанных в обработке, тут получается палка о 2х концах: на больших SMP системах вроде как переключения контекста пропадут, а на UP возрастут многократно).

Я думаю, эти вещи могут быть сбалансированы вручную.

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

alman ★★★
() автор топика
Ответ на: комментарий от alman

> К сожалению, у меня большая иррациональная неприязнь к спин-локам. :) Слишком похожи они на пример, когда вместо ожидания прерывания, в цикле опрашивается порт.

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

> Я думаю, эти вещи могут быть сбалансированы вручную.

> Возьмём пример файловой системы. Обычный запрос read() может потребовать пять обращений к диску. Значит ли это, за время пяти операций вся очередь верхнеуровневых запросов к файловой системе будет стоять? Нет, не значит. Потому что каждый запрос имеет контекст, а файловая система - конечный автомат, которые меняет своё состояние в зависимости от контекста. Проблема латентности решается тем, что короткие запросы, например, требующие одного обращение к диску, могут быть обслужены в промежутках между обработкой предыщего запроса, который, к примеру требует три обращения к диску.

Тут под латентностью я подразумевал вот что:

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

fmj
()
Ответ на: комментарий от fmj

> Что плохого в том, что операция занимающая десяток тактов процессора, будет выполнятся в одно и то-же время, только на одном процессоре?

По моей информации, счёт идёт на тысячи тактов. А чем выше скорость процессора, тем больше оборотов в спинлоке.

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

С этим утвержденем полностью согласен. Однако, почти всегда можно выбрать компромисс для каждой конкретной ситуации.

К примеру, в случае файловой системы оптимален описанный выше способ, потому что время I/O несоразмерно выше времени обработки запроса файловой системой.

В случае реализации TCP/IP, вероятно, оптимально каждый слой OSI выполнять в отдельной нити.

alman ★★★
() автор топика
Ответ на: комментарий от alman

> По моей информации, счёт идёт на тысячи тактов. А чем выше скорость процессора, 
> тем больше оборотов в спинлоке.

Это смотря что спинлочить :) 

Если конструкцию вида

ref(new);

spinlock(ptr->lock); // A

old = ptr->path->to->ref;
ptr->path->to->ref = new;

spinunlock(ptr->lock);  // B

deref(old);

то десятки, а именно -- время за которое выполнится код от точки A до точки B.

fmj
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.