Комментарии 22
Супер. У меня всего два c половиной вопроса
1) Каналы изнутри сами построены на мьютексах?
2) Когда мне использовать мьютекс, а когда буфферизованный канал размером 1?
Тут мне кажется, что разницы между
и
нет, но второй вариант безопаснее. То есть каналы не сложнее мьютекса в самом коде, но безопаснее.
2.5) рантайм Go отлично шедулит горутины когда они засыпают на ожидании данных из канала — делает ли он так же и для мьютексов?
1) Каналы изнутри сами построены на мьютексах?
2) Когда мне использовать мьютекс, а когда буфферизованный канал размером 1?
Тут мне кажется, что разницы между
mutex.Lock()
xxx
mutex.Unlock()
и
<- chan
xxx
1 -> chan
нет, но второй вариант безопаснее. То есть каналы не сложнее мьютекса в самом коде, но безопаснее.
2.5) рантайм Go отлично шедулит горутины когда они засыпают на ожидании данных из канала — делает ли он так же и для мьютексов?
0
Буферизированный канал, по сути, семафор. На счет безопасности, не вижу разницы. Разве что код с мьютексом будет куда очевиднее и скорее всего быстрее.
+1
1. Каналы хитрые. Некоторые операции делаются с оптимистичными блокировками, некоторые чисто на мьютексах.
2. Каналы нужно использовать по-другому. Это не слепая замена мьютексам. Надо на каждый разделяемый ресурс запускать отдельную горутину, которой присылать команды на изменение данных и запросы на чтение. Эта горутина просто исполняет все, о чем её просят, гарантированно последовательно.
По сути ваших примеров кода — аналог мьютекса так можно сделать. За исключением всяких крайних случаев типа двойного вызова Unlock.
2. Каналы нужно использовать по-другому. Это не слепая замена мьютексам. Надо на каждый разделяемый ресурс запускать отдельную горутину, которой присылать команды на изменение данных и запросы на чтение. Эта горутина просто исполняет все, о чем её просят, гарантированно последовательно.
По сути ваших примеров кода — аналог мьютекса так можно сделать. За исключением всяких крайних случаев типа двойного вызова Unlock.
0
1) Каналы используют блокировки, но технически они не являются sync.Mutex блокировкой. Будет точнее сказать, что блокировки для реализации каналов, мютексов, семафоров, рлоков и т.д. используют атомарные процессорные инструкции (типа CaS).
2) Разницы нет в достигнутом результате, но семантически первый вариант корректнее. Откуда мне знать, что у Вас используется именно буферизированный канал размером 1? А когда я вижу mutex.Lock() — то я знаю что это ексклюзивная блокировка.
2.5) «отлично» это слишком сильно сказано. Неплохо — это факт. Но накладные расходы на шедулинг каналов все ещё не дают признать их самым предпочтительным средством разделения доступа. А мютексы рантайм тоже шедулит, если встречает лок.
2) Разницы нет в достигнутом результате, но семантически первый вариант корректнее. Откуда мне знать, что у Вас используется именно буферизированный канал размером 1? А когда я вижу mutex.Lock() — то я знаю что это ексклюзивная блокировка.
2.5) «отлично» это слишком сильно сказано. Неплохо — это факт. Но накладные расходы на шедулинг каналов все ещё не дают признать их самым предпочтительным средством разделения доступа. А мютексы рантайм тоже шедулит, если встречает лок.
0
Если я правильно понимаю, то при работе с каналами невозможно обнаружить взаимоблокировку автоматически, в отличии от мьютексов.
В этом плане мьютексы безопаснее каналов.
В этом плане мьютексы безопаснее каналов.
0
defer mutex.unlock — это, конечно, хорошо, только… Я правильно понимаю, что «правильный» lock_guard в Go сделать не получится?
0
defer unlock даёт те же гарантии, что и lock_guard — при выходе из функции (любом, даже через panic) мьютекс освободится. Я бы сказал, что defer — это оригинальная идея, которая позволяет избежать использования guard'ов и предоставить аналогичную функциональность вообще для любых объектов. Открыли соединение — defer закрыть. Получили блокировку — defer отпустить. Для случаев с более сложной логикой лучше не танцевать с мьютексами, см. статью.
+1
Те же, да не совсем.
lock_guard — это такой способ блокирования мьютекса, что даже самый криворукий программист не сможет забыть его разблокировать.
А забыть написать `defer mutex.Unlock()` можно запросто.
lock_guard — это такой способ блокирования мьютекса, что даже самый криворукий программист не сможет забыть его разблокировать.
А забыть написать `defer mutex.Unlock()` можно запросто.
0
Так же можно забыть и safe_guard создать. Учитывая, что defer unlock пишется на следующей строчке после lock, забыть его ну очень сложно.
+2
Нельзя, если это единственный интерфейс работы с объектом, защищённый мьютексом.
И вообще, в случае mutex guard за эту часть дизайна отвечает разработчик языка/стандартной библиотеки, а не конечный разработчик.
И вообще, в случае mutex guard за эту часть дизайна отвечает разработчик языка/стандартной библиотеки, а не конечный разработчик.
0
Кто ж блокировками заставляет пользователя заниматься? Пользователю снаружи виден метод, а его реализация уже делает все необходимые блокировки. И если она это делает, то делает lock() и defer unlock(). Сразу. Рядом. Без шансов забыть unlock. Об этом речь идёт.
0
Кто ж кто ж, автор статьи пользуется же.
Он пользователь, и для него интерфейс мьютекса — такой. Возможность забыть разблокировку есть.
Он пользователь, и для него интерфейс мьютекса — такой. Возможность забыть разблокировку есть.
0
Вообще говоря, lock_guard дает гарантию блокировки мьютекса при создании на стеке и автоматической разблокировки при выходе из области видимости (а не из функции). При любом выходе, вызывающем раскрутку стека.
0
Это другой вопрос. Я писал лишь о том, что defer и lock_guard — это не вполне эквивалентные механизмы.
0
Можно и mutex.Lock() забыть написать. И вообще забыть на работу пойти.
Особенно в пятницу.
Особенно в пятницу.
+2
что хорошего в этом го? чем он лучше других ЯП?
где нормальные инструменты под него? а не только подсветка синтаксиса.
err :=…
if err != nil {
//log error
return // < — разблокировка произойдет здесь
}
так вроде не пишут, не?
if err := ..; err != nil {
вместо решения проблем, похоже некоторым нравится их создавать
где нормальные инструменты под него? а не только подсветка синтаксиса.
err :=…
if err != nil {
//log error
return // < — разблокировка произойдет здесь
}
так вроде не пишут, не?
if err := ..; err != nil {
вместо решения проблем, похоже некоторым нравится их создавать
-8
> Обратите внимание в этом коде, что для каждого не-экспортированного метода есть аналогичный экспортированный. Эти методы работают как публичный API, и заботятся о блокировках на этом уровне. Далее они вызывают неэкспортированные методы, которые вообще не заботятся о блокировках. Это гарантирует, что все вызовы ваших методов извне будут блокироваться лишь раз и лишены проблемы рекурсивной блокировки.
Копипаста и никем не проверяемые конвенции. Славно. В том же D достаточно объявить класс как synchronized и все публичные методы автоматом будут завёрнуты в локи, а прямой доступ к полям вообще запрещён извне.
Копипаста и никем не проверяемые конвенции. Славно. В том же D достаточно объявить класс как synchronized и все публичные методы автоматом будут завёрнуты в локи, а прямой доступ к полям вообще запрещён извне.
-3
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Танцы с мьютексами в Go