|
0 / 0 / 0
Регистрация: 05.06.2019
Сообщений: 27
|
||||||
Порядок доступа задач (Task) к блокированному объекту (lock)06.07.2022, 22:00. Показов 1162. Ответов 18
Метки нет (Все метки)
Асинхронный канал (System.Threading.Channels) постоянно выстреливает разные задачи (Task), которые выполняются автономно, но те объекты коллекции, с которыми взаимодействует задача обернуты в lock.
Все задачи выстреливаются поочередно, но ни одна не дожидается выполнения предыдущей. Канал обрабатывает огромное количество сообщений и у меня возник вопрос: будут ли эти задачи выполнены в том порядке, в котором они были созданы? Пример: 1) запускается Задача № 1 и блокирует lock. 2) запускается Задача № 2 и встает в очередь, ожидая открытия lock. 3) запускается Задача № 3 и встает в очередь, ожидая открытия lock. 4) завершается Задача № 1 и разблокирует lock. 5) может ли первым зайти в изменяемый объект не Задача № 2, а Задача № 3? И только потом Задача № 2? И как этого избежать? Например, ожидая (await) выполнения задачи #1 и только после этого запускать следующую? Пример кода:
0
|
||||||
| 06.07.2022, 22:00 | |
|
Ответы с готовыми решениями:
18
|
|
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
|
||||
| 07.07.2022, 01:25 | ||||
|
По факту у вас именно это и происходит из-за lock, только очередность не гарантируется.
1
|
||||
|
Модератор
|
|||||||
| 07.07.2022, 08:44 | |||||||
|
kkkoh, во-первых, как написал kolorotur, вам стоит обдумать насколько вам действительно нужна здесь асинхронность.
Во-вторых, вы "злоупотребляете" ConfigureAwait.Если все продолжения должны выполняться не в контексте синхронизации, то заверните всё в один общий таск. Будет и понятнее и проще в коде. Так же, вроде, он имеет смысл только для первого await - последующие уже и так будут выполняться не в контексте синхронизации. Сейчас без компа и проверить не могу. Возможно, kolorotur внесёт ясность. В-третьих, если нужна очерёдность выполнения тасков, то их можно "цеплять" друг за друга. Пищу концептуально:
Из-за await'ов у вас цикл по факту выполняется синхронно. Описанные вам риски возникают только в случае, если метод _collection.UpdateCollection(obj) выполняется очень долго - значительно дольше чем весь остальной код итерации цикла.
2
|
|||||||
|
0 / 0 / 0
Регистрация: 05.06.2019
Сообщений: 27
|
|
| 07.07.2022, 19:24 [ТС] | |
|
К сожалению, асинхронность крайне нужна, так как все взаимосвязано с GUI.
_collection.UpdateCollection(obj) обрабатывает и вправду дольше, чем извлечение объектов из канала. А что касается task.ContinueWith() - мне кажется, что это точно такое же действие, которое происходит и при использовании async/await. Про ConfigureAwait читал бегло, показалось, что нужно всегда указывать ручками в максимальном количестве или использовать какие-то нугеты, вроде Fody
0
|
|
|
Модератор
|
|||||||||
| 07.07.2022, 21:42 | |||||||||
|
Покажите полностью весь метод.
Ну, как бы await использует что-то аналогичное ContinueWith, но напрямую их нельзя сравнивать.ContinueWith - создаёт цепочку последовательных тасков. Что-то аналогичное их очереди. Вам же нужно было последовательное исполнение UpdateCollection, вот в моём примере и создаются последовательные таски с вызовом этого метода, асинхронные относительно самого цикла, в котором они создаются.
0
|
|||||||||
|
0 / 0 / 0
Регистрация: 05.06.2019
Сообщений: 27
|
||||||
| 12.07.2022, 16:28 [ТС] | ||||||
|
Я вас понял.
Конечно, я привел утрированную схему работы. Коллекция - это усложненный ConcurrencyDictionary<long, Model>. Когда в нее падает объект, она дает ссылку на конкретную модель, которую я уже локирую. Более подробно она работает скорее так:
П.С. в тоге переделал все на глубокое async/await
0
|
||||||
|
Модератор
|
|||||||||||||
| 12.07.2022, 17:16 | |||||||||||||
|
То как вы его используете - лишено смысла. Добавлено через 13 минут Но это не замена ContinueWith, а некое преобразование асинхронного метода с использованием в том числе ContinueWith. В грубом приближении:
Добавлено через 4 минуты kkkoh, ContinueWith используется для строго последовательного, но асинхронного, выполнения блоков кода.И по вашему описанию, вам вроде это и было нужно. Поэтому я предложил вам явно создать такую цепочку из методов которые должны асинхронно, но последовательно выполняться.
0
|
|||||||||||||
|
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,233
|
||||||||||||||||||
| 12.07.2022, 17:40 | ||||||||||||||||||
|
С точки зрения логики - это синхронное выполнение. С точки зрения потоков, где будет выполняться continuation code - зависит от текущего планировщика задач и наличия/отсутствия контекста синхронизации. И тут как раз всплывает разница между Task.ContinueWith и просто await. По поводу ConfigureAwait(false) - согласен, тут он лишний, насколько я помню, он затрагивает только поведение для SynchronoizationContext-a. И вообще никаким боком не влияет на поведение TaskScheduler-ов. Насколько я понял, в итоге самый оптимальный ответ дал, как обычно, kolorotur. => (Правда ответ не был нормально понят)
![]()
0
|
||||||||||||||||||
|
Модератор
|
|||
| 12.07.2022, 18:03 | |||
|
Это чтобы избежать проверки на null в каждом цикле. Или нужно для первого элемента делать отдельный блок кода с инициализацией переменной таском.
0
|
|||
|
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,233
|
|
| 12.07.2022, 18:14 | |
|
0
|
|
|
Модератор
|
||
| 12.07.2022, 19:50 | ||
|
Чем лучше? В данном случае, самое оптимальное. По крайней мере мне не пришло в голову ничего лучше. Оба других варианта реализации, что я писал выше, будут затратнее и по коду, и по исполнению.
0
|
||
|
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,233
|
|
| 12.07.2022, 20:02 | |
|
1
|
|
|
0 / 0 / 0
Регистрация: 05.06.2019
Сообщений: 27
|
||||||
| 13.07.2022, 11:24 [ТС] | ||||||
|
По поводу ConfigureAwait(false).
Не совсем понял, почему он тут лишний? Ридер работает в отдельном от коллекции потоке. Коллекция обновляет сотни моделей (в том числе в разных потоках, теоретически). При этом и сама коллекция и ее модели связаны с контекстом синхронизации WinForms (он им задан напрямую при создании). И вроде как все ресурсы, которые я читал, говорят, что ConfigureAwait(false) уменьшает время отработки задачи и в целом ее потребление ресурсов. Потому что каждая проверка ConfigureAwait разворачивается во что-то, наподобие этого:
0
|
||||||
|
403 / 265 / 69
Регистрация: 12.04.2020
Сообщений: 1,404
|
||
| 13.07.2022, 11:37 | ||
|
ставить всегда, если контекст ненужен конечно же
1
|
||
|
Модератор
|
||
| 13.07.2022, 12:43 | ||
|
2) Даже если метод вызывается в потоке с контекстом синхронизации, он имеет значение ТОЛЬКО для кода самого метода, а не для кода методов выполняемых тасками. То есть он не распространяется на вложенные вызовы асинхронных методов (то что у вас ожидают await'ы) и на Task.Run(...). Более точно - все таски выполняются на потоках из пула. Поэтому хоть вы задали ConfigureAwait, хоть не задали - изменить это невозможно. Вот если бы у вас был массивный (тяжёлый, длительный) код вне await и вне тасков, то на его выполнении он теоретически мог бы повлиять. Но у вас нет такого кода. 3) Так как ConfigureAwait(false) принудительно продолжает выполнять код после await в том же потоке в котором выполнялся таск, то есть на пуле потоке, то после await в этом случае уже нет контекста синхронизации. И, соответственно, для следующего await уже даже при ConfigureAwait(true) (значение по умолчанию) всё равно метод продолжит выполнение на пуле потоков. То есть если для первого await задан ConfigureAwait(false), то для последующих задавать его бессмымсленно.Добавлено через 57 секунд kolorotur, написал третий пункт.... Но что-то червь сомнения стал грызть. Всё верно или нет? Добавлено через 5 минут 4) Задавать его для таска который никто не ожидает _ = Task.Run(() => ...., тоже бессмысленно, поскольку он Настраивает объект типа awaiter, используемый для данного объекта Task.await - использует эту настройку для задания потока коду который после него. Можно ещё как-то по иному обрабатывать awaiter после завершения задачи. Но вы не ожидает завершения задачи и, соответственно, не обрабатываете awaiter. Так зачем же его тогда настраивать?
0
|
||
|
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
|
|||||||
| 13.07.2022, 15:07 | |||||||
|
Если асинхронный метод завершился синхронно, то остальной код метода не выносится в продолжение, а отрабатывает дальше как после вызова обычного метода. В этой ситуации контекст синхронизации не меняется и следующий await без вызова ConfigureAwait(false) захватит оригинальный контекст, чего могло не предполагаться во время написания кода. Пример (запускайте в WinForms или WPF для лучшего эффекта):
Но это гарантия так себе — до первого рефакторинга или обновления пакета, а отловить баг или висяк потом может быть сложно.
1
|
|||||||
|
0 / 0 / 0
Регистрация: 05.06.2019
Сообщений: 27
|
|
| 13.07.2022, 16:22 [ТС] | |
|
Я, честно говоря, не понимаю о чем вы.
Тема сложная для полного погружения, но на эти случаи есть рекомендации MSDN. https://docs.microsoft.com/en-... rogramming Оттуда: Use ConfigureAwait(false) when you can Exceptions: Methods that require context
0
|
|
|
Модератор
|
||
| 13.07.2022, 17:36 | ||
|
kolorotur, понял.
Вызываемые асинхронные методы не обязательно дойдут до создания задачи (таска) и могут быть выполнены полностью синхронно. А по остальным пунктам я верно написал (в контексте кода из топа темы)? Добавлено через 2 минуты Но это не относится к вашему коду. По крайней мере в той части, что вы его показали. Добавлено через 3 минуты kkkoh, для уверено ответа вам, необходимо больше информации. Покажите полный код всего метода (из которого вы показали строки в топе), пример его вызова - это нужно чтобы понять возможен ли его вызов из потока с контекстом синхронизации.
0
|
||
| 13.07.2022, 17:36 | |
|
Помогаю со студенческими работами здесь
19
Acer aspire 5552G-N974G64Mikk Проблема с Caps Lock, Num Lock, Scroll Lock Клавиатура мигает всеми тремя индикаторами Caps Lock, Scroll Lock и Num Lock и соответственно не работает! Работа с клавиатурой (клавиши num lock, caps lock, scroll lock) диспетчер задач task manager Завершение массива задач Task с использованием CancellationToken Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие.
Ссылка в Linux — это дополнительная запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая. . .
|
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ВВЕДЕНИЕ
Выполняя задание на управление насосной группой заполнения резервуара,. . .
|
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
|
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога
Финальные проекты на Си и на C++:
hello-sdl3-c. zip
hello-sdl3-cpp. zip
Результат:
|
|
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога
MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
|
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд.
Даже если у вас. . .
|
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает
монорепозиторий в котором находятся все исходники.
При создании нового решения, мы просто добавляем нужные проекты
и имеем. . .
|
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение:
В этой книге («Подход, основанный на вариантах использования») Ивар утверждает,
что архитектура программного обеспечения — это
структуры,. . .
|