LINUX.ORG.RU

А нужны ли все эти ваши гринтреды, корутины, I/O асинхронщина

 , , ,


1

5

и прочие 'костыли/недотреды' на современном то железе и операционных системах в 2018+ годы?

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

Зачем усложнять рантаймы и писать нечитаемою асинхронщину? Зачем пользоваться убогими Node.js, Golang и тому подобным?

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

anonymous
()

лавсанчиг, перелогинся со своим лиспом головного мозга

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

Например, никто не может гарантировать, в каком порядке придут ответы на сетевые запросы.

Блокирующий I/O?
Не, не слышал.

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

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

Shadow ★★★★★
()

Вопрос исключительно удобства.
У меня скрапер на питоне - синхронный, вызывается как тред-потомок из главного треда gui, который асинзронное Wxpython окно, у которого виджеты ловят асинхронно rpc от тредов потомков, чтобы обновлять индикаторы...

Shadow ★★★★★
()
Ответ на: комментарий от i-rinat

Надо будет открутить лимиты во многих местах.

Через ulimit и procfs.

Последний лимит в 125 тысяч на 16 гигов придётся откручивать в ядре Linux.

Вообще-то формула такая:

number of threads = total virtual memory / (stack size*1024*1024)
Стек можно уменьшить(в разумных пределах, разумеется), а swap увеличить. Или оперативки добавить, в конце концов.
(у меня в ноуте 5 лет назад 16 гиг стояло)

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

Вообще-то формула такая:

Это тебе кажется. Попробуй экспериментально определить лимит. Увидишь, что он значительно ниже.

Или оперативки добавить, в конце концов. (у меня в ноуте 5 лет назад 16 гиг стояло)

Круто. Надо докупать железа, чтобы решить созданные проблемы.

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

У меня нет сейчас под руками желёзки с такими параметрами для проведения подобных экспериментов.
А на боевых машинах я экспериментировать не буду.
Вы, видимо, установили размер стека в 128K и поэтому упёрлись на 16 гигах в ~125000. Установили бы стек в 65K и получилось бы уже ~250000.

Надо докупать железа, чтобы решить созданные проблемы

Если вы собираетесь обслуживать одновременно 125000 клиентов на тазике с 16GB ОЗУ, то у вас уже проблемы, большие проблемы.

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

Вы, видимо, установили размер стека в 128K и поэтому упёрлись на 16 гигах в ~125000. Установили бы стек в 65K и получилось бы уже ~250000.

Это высказывание предполагает полное резервирование памяти под стек для каждой нити, что очевидно не происходит. Там лимит связан с struct task_struct и сопутствующими данными.

Если вы собираетесь обслуживать одновременно 125000 клиентов на тазике с 16GB ОЗУ, то у вас уже проблемы, большие проблемы.

Подмена понятий.

i-rinat ★★★★★
()
Ответ на: комментарий от mimimimi

Я как раз за них (нативные) и топлю.

Так нативные треды то же самое только реализовано в ядре, нет?

loz ★★★★★
()
Ответ на: комментарий от i-rinat

Это высказывание предполагает полное резервирование памяти под стек для каждой нити, что очевидно не происходит.

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

Там лимит связан с struct task_struct и сопутствующими данными.

task_struct занимает до 4KB. Плюс ядерный стек на каждый тред, ещё 8KB.
В твоём случае это занимало (12KB * 125000), или около 1.5GB. Это с хорошим запасом.

Подмена понятий.

Какая подмена? Ты создал на каком-то тазике с 16GB мозгов 125000 тредов и расстроился что тебе не дали больше.
А теперь, мол, посмотрите, сколько ОЗУ «улетает в трубу».
При этом ни версии, ни настроек ядра, ни методики проведения эксперимента.

Помимо этого, существуют большие сомнения в том, что такая архитектура вообще чем-то интересна, кроме своей простоты.
Особенно в случае со 100500 тредами, когда накладные расходы на планировку(scheduling) и переключения контекста начинают очень сказываться на общей производительности.

anonymous
()

А нужны ли все эти ваши гринтреды, корутины, I/O асинхронщина

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

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

Проблемы систем 1:1

Не только. А еще у N:M есть свои проблемы, не даром NGPT проиграла NPTL.

Старые солярки и стрекоза с их m:n не ограничивают треды.

Ограничивают, естественно. Бесконечных ресурсов не бывает.

стрекоза с их m:n

A user process contains one or more LWP (Light Weight Process) entities. Each entity represents a user thread under that process.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от anonymous

В твоём случае это занимало (12KB * 125000), или около 1.5GB. Это с хорошим запасом.

Вилами по воде водить это весело, но ты бы в код лучше глянул.

При этом ни версии, ни настроек ядра, ни методики проведения эксперимента.

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

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

Вилами по воде водить это весело,

Вообще-то, это не «вилами по воде», а поиск причин возникших у тебя сложностей, с которыми ты толком не разорался сам, а объяснил чем-то якобы захардкодженым в ядре.

но ты бы в код лучше глянул.

Глянул. Но какое он имеет отношение к вот этому твоему утверждению:

А ещё ты словишь проблем, если захочешь создавать нити для каждого соединения,
...
Последний лимит в 125 тысяч на 16 гигов придётся откручивать в ядре Linux. Причём недостаточно будет просто число поменять в конфиге. Придётся патчить, так как лимит там достаточно захардкожен.

... а?

Я вот в интернетах не нашёл никакого подтверждения этому твоему утверждению.

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

Я вот в интернетах не нашёл никакого подтверждения этому твоему утверждению.

Подтверждение надо искать в коде Linux, а не в интернетах.

Глянул

Не заметно.

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

Подтверждение надо искать в коде Linux, а не в интернетах.

А, ну-да, конечно. В инторнетах ограничения в ядре не принято обсуждать. Только i-rinat-у это позволительно делать.

Не заметно.

Ты какие исходники-то имел в виду?

И ты не забывай, что это тебе нужно доказывать истинность своего утверждения («Без патчей ядра на машине с 16GB ОЗУ возможно создать только ~125K тредов»).
А без доказательств это просто балабольство.

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

Ты какие исходники-то имел в виду?

Linux

Только i-rinat-у это позволительно делать.

Конечно. Я же избранный. А ещё у меня в соседней вкладке открыт https://elixir.bootlin.com с конкретным файлом и функцией в нём, определяющей лимит. Я верю, что это место легко найти минут за десять неспешного поиска.

И ты не забывай, что это тебе нужно доказывать истинность своего утверждения («Без патчей ядра на машине с 16GB ОЗУ возможно создать только ~125K тредов»).
А без доказательств это просто балабольство.

Переживу как-нибудь.

i-rinat ★★★★★
()
Ответ на: комментарий от loz

Извини, оффтоп, ты вроде Red знаешь, не подскажешь, как там слайс от серии взять, типа питоновского: s = s[m:n] без использования copy/part?

anonymous
()
Ответ на: комментарий от i-rinat

Про производительность такого подхода

У тебя там как-то хитро акцептуется незалоченный прослушиваемый сокет. Может из-за этого и чепуха в тесте.

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

В каком ФП языке распараллелить вычисления также просто как #pragma omp parallel? Ну и чтобы скорость выполнения не сильно была ниже говнотехнологии из 60х.

Deleted
()
Ответ на: комментарий от i-rinat

При этом всём современные асинхронные серверы на современном железе могут выжать порядка десятка миллионов одновременных соединений. Возможно, больше.

Только не надо забывать, что если для каждого соединения выполняется какая-то реальная работа или I/O с диска, а не тупо проксирование, то преимущества асинхронности быстро улетучиваются (а недостатки остаются на месте)

annulen ★★★★★
()

Зачем усложнять рантаймы и писать нечитаемою асинхронщину?

Надо просто сделать так, чтобы асинхронных код не выглядел как дерьмо.
/thread

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

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

Да, точно. Я перепутал SO_REUSEADDR и SO_REUSEPORT.

i-rinat ★★★★★
()
Ответ на: комментарий от annulen

преимущества асинхронности быстро улетучиваются

Накладные расходы будут всё ещё меньше. Плюс, если работаешь в одном потоке, автоматически избавляешься от необходимости что-то лочить мьютексами.

i-rinat ★★★★★
()
Ответ на: комментарий от anonymous

Лол, надо использовать `copy/part`, семантически это одно и то же - питон тоже создает копию, просто там синтаксис подкрутили.

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

Объясни? Я спрашиваю, потому что например Эрланг имеет свой шедулер и свои треды которыми по максимуму управляет, понятно что в итоге это мапится на нативные, но по-моему тут вся разница это юзерспейс vs кернелспейс.

loz ★★★★★
()
Последнее исправление: loz (всего исправлений: 1)
Ответ на: комментарий от i-rinat

Накладные расходы будут всё ещё меньше.

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

Плюс, если работаешь в одном потоке, автоматически избавляешься от необходимости что-то лочить мьютексами.

Это актуально только если есть общее состояние и воркеров, что чаще всего не обязательно.

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

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

Тогда как с тредами планировщик ОС все разрулит - все ядра загрузятся по максимуму и «быстрые» или «важные» запросы не будут ждать в очереди за «медленными» или «неважными»

annulen ★★★★★
()
Ответ на: комментарий от i-rinat

Что касается I/O: вот начал твой процесс читать файл с диска, и все заблокировалось на момент времени, проц простаивает так как конкурирующих потоков нет. Да я знаю про POSIX AIO, но те же разработчики Nginx на Линуксе его не советуют, и запилили тред-пул

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

Забавно, что ты Nginx аривёл в пример. Тредпул они запилили, а от асинхронности так и не отказались.

Что касается posix aio, его под линуксом все избегают, потому что он там только для галочки: на фоне создаётся тред, в котором запускаются те же блокирующие вызовы. По моему, про него в приличном обществе вообще вспоминать не стоит.

i-rinat ★★★★★
()
Ответ на: комментарий от annulen

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

Только вот пул потоков фиксированный, соединения на них мапятся не один к одному, а значит в деле та самая асинхронность.

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

Тредпул они запилили, а от асинхронности так и не отказались.

Потому что nginx - классический пример прокси, о чем я и говорил в первом посте

По моему, про него в приличном обществе вообще вспоминать не стоит.

Есть же и другие ОС, BSD например

annulen ★★★★★
()
Ответ на: комментарий от i-rinat

Пул потоков фиксированный, но то о чем я говорил это k*N потоков (процессов) на N прцессорных ядер. Если задача упирается в проц, то оптимальное k будет около единицы, если в диск или в коннекты к базе или к другому внешнему ресурсу такого типа - то небольшое число

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

Блин, верно, я питон плохо знаю, а в семантике Го это невозможно сделать, без копирования?

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

но то о чем я говорил это k*N потоков (процессов) на N прцессорных ядер.

И опять-таки число потоков определяется числом ядер, а не числом задач. Пока нет одного потока на задачу, будет асинхронность со всеми её проблемами.

Я плохо понимаю, что ты пытаешься сказать.

i-rinat ★★★★★
()
Ответ на: комментарий от loz

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

anonymous
()

Даешь интенсивным вычислениям системные потоки, а для IO даешь асинхронщину, гринтреды! Корутины не даешь.

dave ★★★★★
()
Ответ на: комментарий от i-rinat

Пока нет одного потока на задачу, будет асинхронность со всеми её проблемами.

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

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

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

В целом я бы сказал что это не очень нужно, ты можешь все так же передавать индексы в пределах которых надо работать. И большинство функций принимают такой аргумент, например тот же `copy/part`.

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

Да, но я могу сделать слайс - b: skip a x, и работать с b в другой функции, не передавая индекс, а вот хвост обрезать не могу, неудобно. На счет «не нужно» - не согласен, фильтруя массив на месте можно отбросить ненужное, а тут - фиг.

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

но я могу сделать слайс - b: skip a x

Это не слайс, ты просто подвинул индекс. Получивший `b` может сделать `b: head b` и что угодно дальше.

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

Верно, но по факту, передать в функцию вторую половину серии я могу, а первую - только с передачей еще и индекса.

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

Понял, ну, по крайней мере, не буду искать несуществующее, спасибо)

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

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

И k*N долгих запросов сделают серверу DoS.

i-rinat ★★★★★
()
Ответ на: комментарий от loz

А, кажется, таки есть способ, деструктивный и многословный правда, но хоть так: remove/part skip a n length? a

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