LINUX.ORG.RU

История изменений

Исправление shahid, (текущая версия) :

другие файберы вытеснят ожидающий таск с треда и займутся другими делами

Очень грубо говоря, есть thread-pool и очередь задач.
В пуле кол-во потоков равно кол-ву CPU.
Очередь задач раскидывает задачи по свободным потокам, по возможности учитывая cpu cache coherence.

В случае асинхронной работы с базами будет маленькая задача «отправить запрос к базе» и листенер в netty, который потом отправит на исполнение новую задачу: «обработать результат запроса». Т.е. «вытеснения» как такового нет, и паразитные context switch снижены до минимума. По такому принципу устроен например play framework. Но такая работа на блокирующем io заблокирует весь сервис очень быстро, и для блокирующих операций тут нужен отдельный thread-pool (ExecutionContext).

На erlang есть глобальный thread-pool легких тредов, где их обычно тысячи и миллионы. Размер thread-pool задается параметром при запуске beam (это vm erlang'а). Большой thread pool жрёт много RAM и повышает долю паразитных, хоть и легковесных, переключений контекста на CPU. Я не считаю, что модель многопоточности erlang хороша: неоправданные расходы на RAM, на серьезной нагрузке ощущаются потери на переключениях и нужно вручную педалировать per-thread GC, для обмена сообщениями между потоками используется memcpy() либо сериализация в блобы. Но из-за отсутствия изменяемых типов данных в erlang и глобального GC что-то лучше придумать там проблематично.

Исправление shahid, :

другие файберы вытеснят ожидающий таск с треда и займутся другими делами

Очень грубо говоря, есть thread-pool и очередь задач.
В пуле кол-во потоков равно кол-ву CPU.
Очередь задач раскидывает задачи по свободным потокам, по возможности учитывая cpu cache coherence.

В случае асинхронной работы с базами будет маленькая задача «отправить запрос к базе» и листенер в netty, который потом отправит на исполнение новую задачу: «обработать результат запроса». Т.е. «вытеснения» как такового нет, и паразитные context switch снижены до минимума. По такому принципу устроен например play framework. Но такая работа на блокирующем io заблокирует весь сервис очень быстро, и для блокирующих операций тут нужен отдельный thread-pool (ExecutionContext).

На erlang есть глобальный thread-pool легких тредов, где их обычно тысячи и миллионы. Размер thread-pool задается параметром при запуске beam (это vm erlang'а). Большой thread pool жрёт много RAM и повышает долю паразитных, хоть и легковесных, переключений контекста на CPU. Я не считаю, что модель многопоточности erlang хороша: неоправданные расходы на RAM, на серьезной нагрузке ощущаются потери на переключениях и нужно вручную педалировать per-thread GC, для обмена сообщениями между потоками используется memcpy() либо сериализация в блобы. Но из-за отсутствия изменяемых типов данных в erlang что-то лучше придумать там проблематично.

Исходная версия shahid, :

другие файберы вытеснят ожидающий таск с треда и займутся другими делами

Очень грубо говоря, есть thread-pool и очередь задач.
В пуле кол-во потоков равно кол-ву CPU.
Очередь задач раскидывает задачи по свободным потокам, по возможности учитывая cpu cache coherence.

В случае асинхронной работы с базами будет маленькая задача «отправить запрос к базе» и листенер в netty, который отправит на исполнение новую задачу: «обработать результат запроса». Т.е. «вытеснения» как такового нет, и паразитные context switch снижены до минимума. По такому принципу устроен например play framework. Но такая работа на блокирующем io заблокирует весь сервис очень быстро, и для блокирующих операций тут нужен отдельный ExecutionContext.

На erlang есть глобальный thread-pool легких тредов, где их обычно тысячи и миллионы. Размер thread-pool задается параметром при запуске beam (это vm erlang'а). Большой thread pool жрёт много RAM и повышает долю паразитных, хоть и легковесных, переключений контекста на CPU. Я не считаю, что модель многопоточности erlang хороша: неоправданные расходы на RAM, на серьезной нагрузке ощущаются потери на переключениях и нужно вручную педалировать per-thread GC, для обмена сообщениями между потоками используется memcpy() либо сериализация в блобы. Но из-за отсутствия изменяемых типов данных в erlang что-то лучше придумать там проблематично.