Подтвердить что ты не робот

Доступ к карте с одновременным доступом к карте Голан с диапазоном

У меня есть карта с объектами, которые должны быть выпущены до очистки карты. Я испытываю искушение перебирать карту и удалять/отпускать объекты, когда я прохожу через нее.

Вот пример макета https://play.golang.org/p/kAtPoUgMsq

Поскольку единственный способ итерации карты - это диапазон, как мне синхронизировать несколько производителей и нескольких потребителей?

Я не хочу читать блокировку карты, так как это сделает невозможным удаление/изменение ключей во время итерации.

4b9b3361

Ответ 1

Существует множество способов очистки вещей от map без доступа к карте. Что работает для вашего приложения, зависит от того, что он делает.

0) Просто заблокируйте карту во время работы над ней. Если карта не слишком большая или у вас есть некоторый толерантность к задержкам, она быстро выполняет задание (с точки зрения времени, которое вы тратите на нее), и вы можете переходить к размышлению о других вещах. Если это станет проблемой позже, вы можете вернуться к проблеме.

1) Скопируйте объекты или указатели и очистите карту, удерживая блокировку, затем отпустите объекты в фоновом режиме. Если проблема в том, что медленность освобождения будет удерживать замок долгое время, это простой способ для этого.

2) Если эффективные чтения в основном имеют значение, используйте atomic.Value. Это позволяет полностью заменить одну карту новой и другой. Если записи составляют, по существу, 0% от вашей рабочей нагрузки, эффективный считывает баланс стоимости создания новой карты при каждом изменении. Это редко, но это происходит, например, encoding/gob имеет глобальную карту типов, управляемых таким образом.

3) Если ни один из них не делает все, что вам нужно, настройте, как вы храните данные (например, осколочно карту). Замените карту на 16 карт и хеш-ключи самостоятельно, чтобы решить, к какой карте принадлежит вещь, а затем вы можете заблокировать один осколок за раз, для очистки или любой другой записи.

Также существует проблема гонки между выпуском и использованием: goroutine A получает что-то с карты, B очищает карту и освобождает вещь, A использует выпущенную вещь.

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

Другой - терпеть последствия рас, если они известны и не катастрофичны; например, одновременный доступ к net.Conn явно разрешен его документами, поэтому закрытие подключенного к использованию соединения может привести к ошибке запроса на него, но не приведет к поведению приложения undefined. Вы действительно должны быть уверены, что знаете, в чем вы тогда попадаете, потому что многие доброкачественные расы не являются.

Наконец, возможно, ваше приложение уже гарантирует, что не будут удалены неиспользуемые объекты, например. там безопасно поддерживается отсчет ссылок на объекты и освобождаются только неиспользуемые объекты. Тогда, конечно, вам не о чем волноваться.

Возможно, возникает соблазн попытаться заменить эти блокировки на каналы каким-то образом, но я не вижу никаких преимуществ от этого. Приятно, когда вы можете проектировать свое приложение, думая главным образом о связях между процессами, а не об общих данных, но когда у вас есть общие данные, нет смысла притворяться иначе. Исключение небезопасного доступа к общим данным - это блокировки для.

Ответ 2

Вы не указываете все требования (например, может ли выпуск нескольких объектов происходить одновременно и т.д.), но самое простое решение, о котором я могу думать, это удалить элементы и запустить версию goroutine для каждого из удаленных элементов:

for key := range keysToRemove {
    if v, ok := m[k]; ok {
        delete(m, k)
        go release(k, v)
    }
}

Ответ 3

Обновление августа 2017 года (golang 1.9)

Теперь у вас есть новый Map тип sync - это параллельная карта с нагрузками, хранилищами и удалениями с амортизированной постоянной нагрузкой.
Для нескольких goroutines безопасно одновременно вызывать методы Map.


Оригинальный ответ № 2016

Я не хочу читать блокировку карты

Это имеет смысл, поскольку удаление из карты считается операцией записи и должно быть сериализовано со всеми другими чтениями и записью. Это означает, что блокировка записи завершена. (источник: этот ответ)

Предполагая наихудший сценарий (несколько авторов и читателей), вы можете взглянуть на реализацию orcaman/concurrent-map, которая имеет a Remove() method, используя несколько sync.RWMutex, потому что, чтобы избежать узких мест блокировки, эта параллельная карта погружается в несколько (SHARD_COUNT) map осколки.
Это быстрее, чем использование только одного RWMutex как в этом примере.