Здравствуйте, Serginio1, Вы писали:
N>>>>Эээ... после выполнения захвата лока (речь об этом, да?) как раз лучше не отдавать управление, а сделать максимум действий во время захвата. А до него — если лок занят — то раз ждём, надо оповестить шедулер о том, что есть отличный повод запустить другую задачу.
S>>> Я как раз про то, что если lock короткий, то не стоит передавать управление на другой поток.
N>>Так передавать когда? До него или после? В случае удачного захвата или неудачного?
S>При удачном захвате стоит дождаться освобождения, что бы другие потоки могли воспользоваться свободным монитором
Вероятность прерывания в этот момент для интерактивной нитки (который больше спит и реагирует на события, чем ест процессор) крайне мала (при сколь-нибудь умном шедулере, разумеется).
Более того, в случае await-based построения работы вероятность насильственного переключения со стороны ОС выше, если нет возможности её явно проинструктировать "тут воздержись, а тут больше свободы" — если гружёный процесс держит всю активность в нескольких нитках по количеству хартов — с точки зрения ОС это одна неуправляемая прожора, и когда переключать на соседей — она просто не в курсе.
N>>Да, проблема есть (хотя про "основной источник проблем с производительностью" тут загнули, случай он разный бывает). Но вы никак от этого не избавитесь ни шедулингом, ни переходом на await, пока вам потребуется ровно та же синхронизация.
S> Я тебе привел пример аналога LockAsync. Поток ничего не ждет, а по событию запускается из пула потоков. Вот пример асинхронной очереди
S>AsyncProducerConsumerCollection
S>Просто привел пример с использованием ValueTask вместо Task
Так с точки зрения ОС что поможет тут осознать, когда можно переключать на другую нить вообще другого процесса, а когда лучше этого не делать, потому что захвачен важный лок (и даже в случае асинхронных локов это блокирует другие задачи)?
Я б ожидал каких-то явных системных вызовов, но тут про них ни слова.
N>>Если так, то та же цена реально размазана по остальной работе: с данными в куче всегда дороже работать, чем с данными на стеке или тем более в регистрах: аллокация, GC где-то после, разыменование указателей (спрятанных в ссылках дотнетов), заметно худшее кэширование, потому что в стеке данные сидят плотно, и наверняка ещё и пара сотен байт вершины стека в кэшах процессора.
S> Угу который при переходе на новый поток сбрасывается.
Кто сбрасывается? Кэш процессора? Зачем? Даже с мерами против Meltdown/Spectre кэш сбрасывается при переключении между процессами, а не между нитками одного процесса. Хотя о чём и, главное, чем думают тут в MS, я не в курсе.
S>У меня вопрос если все так прекрасно с переключением потоков, то зачем делают все, что бы отказаться от потоков и использовать очередь потоков?
Кто сказал, что "всё прекрасно"? Я не знаю, откуда и как вы делаете такие выводы.
И что это "все", что делают чтобы отказаться? В основном делают там, где просто неудобно/дорого по другим причинам возлагать это на ОС.
Да, есть цена на переключение, даже вход и выход из системного вызова чего-то стоит, и на Windows эта цена сильно выше, чем на Linux. Может, потому для Windows и стараются сократить эти переключения. В Linux я не вижу такого активного стремления, если где-то такое делают, то в рантаймах со сложной собственной логикой и полностью "управляемым" выполнением (Go, Erlang).
N>>Не может быть квадратных кругов и круглых квадратов. Если с данными надо работать, то для этого нужен доступ к ним. Если нужен доступ, их надо прочитать из памяти и записать в память, с соответствующей ценой. Я бы предпочёл, чтобы компиляция хранила максимум в регистрах процессора, а что не помещается — максимум на стеке: не будет дурных потерь скорости. А если при этом само переключение формально дороже — тоже не страшно, записать компактно пару сотен байт и потом прочитать — эффективнее, чем размазывать их по десяткам кэш-строк.
S>Ну класс если используешь Value типы тоже будут компактно расположены, а не валуе типы что на стеке, что не на нем все равно в куче
То есть в дотнет ещё не завезли escape analysis? (сомневаюсь)
S>>>>>Конечно зависит от длительности задач, но если задачи непродолжительные, то пул потоков может и не переключаться а выполнять очередь заданий.
N>>>>Тоже не понимаю, при чём тут эта реплика.
S>>> В том, что с использованием пула потоков сводит к минимуму переключение потоков
N>>Так не от желания конкретной задачи тут зависит, а от того, будет ли тот лок свободен.
S>Вот ссылочка из предыдущего сообщения AsyncSemaphore
S>Если lock занят то возвращается Task и ожидается пока не вызовется SetResult
S>Никакой остановки потока нет. Да внутри конечно есть короткий lock который нужно заменять на SpinLock
Почему это "нужно заменять"? Обычный lock настолько неэффективен?