Re[11]: Горутины и потоки
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 02.07.21 07:25
Оценка:
Здравствуйте, netch80, Вы писали:

N>Здравствуйте, Serginio1, Вы писали:


N>>>Эээ... после выполнения захвата лока (речь об этом, да?) как раз лучше не отдавать управление, а сделать максимум действий во время захвата. А до него — если лок занят — то раз ждём, надо оповестить шедулер о том, что есть отличный повод запустить другую задачу.

S>> Я как раз про то, что если lock короткий, то не стоит передавать управление на другой поток.

N>Так передавать когда? До него или после? В случае удачного захвата или неудачного?

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


N>Да, проблема есть (хотя про "основной источник проблем с производительностью" тут загнули, случай он разный бывает). Но вы никак от этого не избавитесь ни шедулингом, ни переходом на await, пока вам потребуется ровно та же синхронизация.


Я тебе привел пример аналога LockAsync. Поток ничего не ждет, а по событию запускается из пула потоков. Вот пример асинхронной очереди
AsyncProducerConsumerCollection
Просто привел пример с использованием ValueTask вместо Task

S>>>>Для примера в эпоху до async/await поток ждет выполнения асинхронной операции.

S>>>>async/await берет на себя сохранения данных внутри класса (стек не нужен) и строит автомат и тот же поток который выполнял данную задачу, запускает другую. Нет никаких переключений.

N>>>А что, вот эти все "берёт на себя сохранения данных внутри класса" и аналогичное восстановление, по-вашему, не переключение? А что оно такое тогда?

S>> Там нет восстаеовления ибо данные хранятся в куче.

N>Если так, то та же цена реально размазана по остальной работе: с данными в куче всегда дороже работать, чем с данными на стеке или тем более в регистрах: аллокация, GC где-то после, разыменование указателей (спрятанных в ссылках дотнетов), заметно худшее кэширование, потому что в стеке данные сидят плотно, и наверняка ещё и пара сотен байт вершины стека в кэшах процессора.

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

N>Не может быть квадратных кругов и круглых квадратов. Если с данными надо работать, то для этого нужен доступ к ним. Если нужен доступ, их надо прочитать из памяти и записать в память, с соответствующей ценой. Я бы предпочёл, чтобы компиляция хранила максимум в регистрах процессора, а что не помещается — максимум на стеке: не будет дурных потерь скорости. А если при этом само переключение формально дороже — тоже не страшно, записать компактно пару сотен байт и потом прочитать — эффективнее, чем размазывать их по десяткам кэш-строк.


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

N>>>С точки зрения логики управления выполнением — именно для тех случаев, когда шедулер узнал, что ответа для await сейчас нет и надо дать кому-то управление.

N>>>С точки зрения исходного кода — чтобы писать его максимально линейно.
S>> Линейно то и раньше писали, только внутри были всякие евенты и остановка потока.

N>Я говорю про варианты без такой остановки (если переключение, то оно минимально видно в ОС).


N>>>Переключений в нём, в идеале, столько же, сколько в аналогичном коде на коллбэках или промисах.

S>> Ну в итоге то колбеки запускаются из пула потоков.

N>Ну это уже дотнетовая специфика и не обязательно так везде. И это не обязательно удобно. Я во многих случаях хотел бы ограничить такое явно только тем же тредом, который вызвал исходную операцию.


S>>>>Ну и замена всяких Lock на ManualResetValueTaskSource

S>>>>http://rsdn.org/forum/dotnet/8030645.1
Автор: Serginio1
Дата: 16.06.21

S>>>> https://stackoverflow.com/questions/66387225/awaiting-a-single-net-event-with-a-valuetask

N>>>Я что-то не могу это раскурить. Какой смысл в его применении?

S>> Смысл в том, что замена lock на lockAsync. То есть нет никакого ожидания потока

N>Если оно сделано умно (с попытками захвата до переключения) — отлично.


S>>>>Конечно зависит от длительности задач, но если задачи непродолжительные, то пул потоков может и не переключаться а выполнять очередь заданий.

N>>>Тоже не понимаю, при чём тут эта реплика.
S>> В том, что с использованием пула потоков сводит к минимуму переключение потоков

N>Так не от желания конкретной задачи тут зависит, а от того, будет ли тот лок свободен.

Вот ссылочка из предыдущего сообщения AsyncSemaphore

Если lock занят то возвращается Task и ожидается пока не вызовется SetResult
Никакой остановки потока нет. Да внутри конечно есть короткий lock который нужно заменять на SpinLock
и солнце б утром не вставало, когда бы не было меня
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.