так и синхронной среде. Проблема в том, что если я использую мьютекс из std, то у меня потенциально лочится экзекьютор в асинке. Если из tokio::sync, то мне приходится плодить отдельный рантайм для block_on() над асинхронным мьютексом. Есть ли вообще реализации sync <=> async мьютекса ?
Асинхронный мьютекс почти никогда не нужен
А если у тебя синхронный мьютекс держится между вызовами .await, которые потенциально долгие?
Задуматься о дизайне.
Ответ уровня - Доктор у меня болит когда я делаю так - Не делайте так больше
Ну, да, примерно. Если у тебя в коде появились асинхронные мьютексы, то, скорее всего, тебе дальше будет больно. В этот момент имеет смысл остановиться и подумать, нельзя ли это выразить по-другому.
А есть вообще причина не использовать асинхронные мьютексы вообще везде? Ну то есть я реально хочу узнать почему бы их не использовать вместо синхронных (Пы. сы. я юзаю синхронные примитивы в асинхронном коде по рекомендации токио, но просто хочу узнать причину не юзать асинхронные)
Ровно та причина, по которой они вообще существуют — их можно держать между await-поинтами. Синхронизация резко становится сложнее, если пока ты держишь мьютекс, может произойти что угодно ещё в том же треде. Ну и они несколько менее производительные, но это не так важно само по себе.
Ай гесс, дис ризон - "The feature that the async mutex offers over the blocking mutex is the ability to keep it locked across an .await point. This makes the async mutex more expensive than the blocking mutex, so the blocking mutex should be preferred in the cases where it can be used."
Всегда, ещё задолго до async/await, когда человечество знало только потоки — всегда всех предупреждали против долгого лока мьютекса. Потому что пока мьютекс залочен, работает только один поток, и многопоточная программа превращается в однопоточную. Только медленнее, потому что ещё накладные расходы на мьютекс. Это никогда не имело смысла, и прозрачно намекало на неудачный дизайн.
Ну то есть если мне нужно держать лок в течении нескольких .await’ов, то лучше юзать асинхронный?
Да, но ещё лучше — сделать так, чтобы его не надо было держать в течение нескольких await-ов.
Не знаю как можно пройтись по коллекции и вызвать у каждого элемента асинхронную функцию так, чтобы лок на колекцию не держать
Зачем держать лок на коллекцию?
*Один поток, из всех, которые работают с этими же данными Или я чего-то про мьютексы не знаю и они все потоки останавливают?
Ну мне нужно пройтись по Arc<Mutex<Vec<_>>> допустим. В нее могут добавлять элементы и убирать. Как обойтись без мьютексов и лока на них если нужна операция, выполняющаяся на всех иногда?
Да, из всех, которые работают с этими данными. Но если Вам нужно, чтобы с этими данными работал только один поток — зачем запускать несколько и лочить их мьютексом?
Точно ли это обязано быть Vec?
Не особо понял. У меня есть состояние приложение AppState через которое все компоненты общаются. Каждый компонент в своей таске запущен и может модифицировать AppState. Как без примитивов синхронизации тут обойтись?
Зависит от конкретной нагрузки Можно, например, запустить главный стейт в отдельной таске и посылать ему сообщения по каналам
В моем случае это hashmap в основном, но. я просто пример коллекции привел
Это и есть плохой дизайн. 🤷♀️
жирнющие match event мне тоже не очень нравятся (а в моем случае их реально много)
попробуй использовать канал вместо мьютекса некоторые виды каналов позволяют взаимодействовать между двух сред даже канал из std синхронный может подойти (unbounded), зависит что и откуда ты посылаешь и где принимаешь по-сути токийский мутекс это тоже очередь у тебя взаимодействие между потоками, поэтому не надо им иметь общую блокировку, пусть общаются сообщениями по -поводу синк-мутекса: если он нужен чтобы защитить данные, т.е. взять мутекс, записать в переменную и тут же отпустить, то подойдет и синхронный, потому что запись в память быстро происходит
Там основная задержка - не запись в память, а лок мутекса. Несколько (десятков) миллионов локов в секунду могут загрузить процессор на 100%. Так что с ними надо осторожно
хорошее замечание
На самом деле, решил проблему чисто архитектурно. У меня лок происходит в цикле (внутри асинка). Как только я получаю данные из структуры, я под них спавню таску. Поэтому, анлок получается практически инстантным. А так- спасибо, не подумал о каналах, буду иметь в виду.
Обсуждают сегодня