Информация об изменениях

Сообщение Re[18]: .net core и async lock от 13.04.2021 21:33

Изменено 13.04.2021 23:27 vdimas

Re[18]: .net core и async lock
Здравствуйте, artelk, Вы писали:

V>>Еще часто оперируют TLS-хранилищем, перетасовывая стек ExecutionContext, что например, порой требует даже постоянной переустановки культуры текущему потоку перед каждым чихом.

V>>(в нейтиве культура привязана к "физическому потоку", то бишь потоку уровня ОС, а в дотнете — к логическому).
A>ExecutionContext хранит AsyncLocals, не хотелось бы их потерять.

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

Всё-таки, AsyncLocals это даже хуже чем TLS, т.е. совсем уж костыль, который крайне редко используется.


V>>В общем, использовать ValueTask — экономить на спичках.

A>ValueTask оптимизирует случай, когда задача завершена синхронно и он позволяет избежать создания объекта Task в куче. Для этого и создан.

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


V>>Отличия от FIFO чаще являются светошумовыми эффектами разных приоритетов, например, при инверсии приоритетов, когда низкоприоритетному потоку дают больше квантов времени, чем его соседям по приоритету, чтобы он освободил ресурс для высокоприоритетного потока.

A>Не понял причем тут очередь потоков.

А очередь каких сущностей ожидает готовности традиционного семафора?


V>>В общем, навскидку сложно сказать, насколько это будет дешевле обычной сериализации доступа через мьютекс (критическую секцию) к состоянию асинхронного семафора, ведь в случае оперирования более легковесными чем Task объектами эта блокировка будут весьма короткой, т.е. вероятность столкновения на ней будет мала.

A>Это ты об операции добавления в очередь пишешь? Не понятно как к этому относится тяжеловесность\легковесность объектов Task или их аналогов.

Этот абзац отвечал на предложение о lock-free реализации очереди.
Алгоритмы lock-free сами по себе достаточно многословны, тут можно делать выводы только через сравнительное тестирование вариантов реализации.

Например, критическая секция (и монитор на основе этой функциональности в дотнете) не дёргает примитивы синхронизации в отсутствии столкновений потоков.
В общем, полно сценариев, когда короткие блокировки заруливают lock-free алгоритмы. Степень заруливаемости зависит от отношения длительности блокировки к среднему периоду м/у обращениями к общему ресурсу.


V>>Я бы ограничился одним массивом.

V>>В реальной жизни конкурентность к ресурсу обычно невысока — от силы десятки или единицы сотен "заявок".
A>Как одним? Давая обясню проблему, которую я имел ввиду. Вот вызвал клиент WaitAsync и получил назад MyValueTask. Далее он может его сохранить где-то у себя и проверить у него свойство IsCompleted через час.

IsCompleted не является обязательным для реализации своих awater-ов.

Собсно, на всех углах одно время говорилось (когда многопоточное программирование только набирало популярность) — избегайте опрашивать состояние примитивов синхронизации, это плохая практика.
Ну и вот, можно прямо на уроне дизайна возможность опроса не давать.

Для примера, критическая секция не даёт возможность опросить своё состояние.

Соответственно, семафору или возвращаемой прокси-структуре (при вызове ConfigureAwait(bool) или вызове блокировки с таймаутом) можно будет делать только await.


A>И значение должно быть верным. Т.е. элемент массива должен быть прибит гвоздями к своему "владельцу" MyValueTask и не может быть переиспользован даже если последний давно стал Complete.


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

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

Т.е. выиграть в эффективности в некоем сценарии обычно можно за счёт усиления ограничений, а не за счёт их ослабления.
Re[18]: .net core и async lock
Здравствуйте, artelk, Вы писали:

V>>Еще часто оперируют TLS-хранилищем, перетасовывая стек ExecutionContext, что например, порой требует даже постоянной переустановки культуры текущему потоку перед каждым чихом.

V>>(в нейтиве культура привязана к "физическому потоку", то бишь потоку уровня ОС, а в дотнете — к логическому).
A>ExecutionContext хранит AsyncLocals, не хотелось бы их потерять.

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

Всё-таки, AsyncLocals это даже хуже чем TLS, т.е. совсем уж костыль, который крайне редко используется.


V>>В общем, использовать ValueTask — экономить на спичках.

A>ValueTask оптимизирует случай, когда задача завершена синхронно и он позволяет избежать создания объекта Task в куче. Для этого и создан.

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


V>>Отличия от FIFO чаще являются светошумовыми эффектами разных приоритетов, например, при инверсии приоритетов, когда низкоприоритетному потоку дают больше квантов времени, чем его соседям по приоритету, чтобы он освободил ресурс для высокоприоритетного потока.

A>Не понял причем тут очередь потоков.

А очередь каких сущностей ожидает готовности традиционного семафора?


V>>В общем, навскидку сложно сказать, насколько это будет дешевле обычной сериализации доступа через мьютекс (критическую секцию) к состоянию асинхронного семафора, ведь в случае оперирования более легковесными чем Task объектами эта блокировка будут весьма короткой, т.е. вероятность столкновения на ней будет мала.

A>Это ты об операции добавления в очередь пишешь? Не понятно как к этому относится тяжеловесность\легковесность объектов Task или их аналогов.

Этот абзац отвечал на предложение о lock-free реализации очереди.
Алгоритмы lock-free сами по себе достаточно многословны, тут можно делать выводы только через сравнительное тестирование вариантов реализации.

Например, критическая секция (и монитор на основе этой функциональности в дотнете) не дёргает примитивы синхронизации в отсутствии столкновений потоков.
В общем, полно сценариев, когда короткие блокировки заруливают lock-free алгоритмы. Степень заруливаемости зависит от отношения длительности блокировки к среднему периоду м/у обращениями к общему ресурсу.


V>>Я бы ограничился одним массивом.

V>>В реальной жизни конкурентность к ресурсу обычно невысока — от силы десятки или единицы сотен "заявок".
A>Как одним? Давая обясню проблему, которую я имел ввиду. Вот вызвал клиент WaitAsync и получил назад MyValueTask. Далее он может его сохранить где-то у себя и проверить у него свойство IsCompleted через час.

IsCompleted не является обязательным для реализации своих awater-ов.

Собсно, на всех углах одно время говорилось (когда многопоточное программирование только набирало популярность) — избегайте опрашивать состояние примитивов синхронизации, это плохая практика.
Ну и вот, можно прямо на уроне дизайна возможность опроса не давать.

Для примера, критическая секция не даёт возможность опросить своё состояние.

Соответственно, семафору или возвращаемой прокси-структуре (при вызове ConfigureAwait(bool) или вызове блокировки с таймаутом) можно будет делать только await.


A>И значение должно быть верным. Т.е. элемент массива должен быть прибит гвоздями к своему "владельцу" MyValueTask и не может быть переиспользован даже если последний давно стал Complete.


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

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

Т.е. выиграть в эффективности в некоем сценарии обычно можно за счёт усиления ограничений, а не за счёт их ослабления.