Как стать автором
Обновить

Комментарии 9

Спасибо большое, обязательно гляну

Ради интереса попробовал поменять местами запуски бенчмарка и получил противоположный результат:

BenchmarkProcessUsingMutex-8     1    3627994802 ns/op
BenchmarkProcessUsingAtomic-8    1    3707776703 ns/op

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

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

Тут синхронизация не нужна вовсе. Это же мап-редьюс. Много источников собираем в один канал и результаты этого канала суммируем. Если, вдруг, по какой-то причине надо суммировать параллельно, то надо делать суммы во многих рутинах и потом отправлять в одну для итога.

Используя каналы можно решить данную задачу и будет наверное проще это сделать.
Я сильно не погружался еще в каналы(я на golang не так давно пишу), но если посмотреть runtime/chan.go, то можно увидеть, что в каналах используется mutex(там не sync.Mutex, но все равно используется mutex). Поэтому, если выбирать каналы, то получается выбирать mutex. Но mutex под капотом использует атомики, поэтому если задачу можно решить с использованием atomic, то скорей всего это будет более оптимальное решение по времени, чем с использованием mutex(но все нужно мерить в каждой конкретной задаче, может быть прирост будет минимальный или его вообще не будет).
В этой статье я хотел показать как пользоваться атомиками для float64 и ничего больше, я не хотел показать этой статьей, что решение моей задачи оптимально именно с использованием атомиков(в каждом конкретном случае нужно мерить и находить компромис между поддерживаемым и читаемым кодом и скоростью его выполнения).
Решение с атомиками, получилось не сильно сложное, как мне показалось, поэтому его можно рассмотреть при выборе решения задачи.

Вы в канал будете писать итоговую сумму для каждого worker, это выйдет намного быстрее, так как вместо countTasks вызовов atomic.*, у вас будет countWorkers вызовов Mutex.Lock/Unlock (то есть намного меньше).

Если собирать в каждом воркере свою сумму и при завершении воркера суммировать все результаты, то мы не знаем суммарное количество до завершения, а часто хочется иметь прогресс(сейчас 50 ошибок и тотал 50123,12), если не нужно знать суммарное количество до завершения, то суммировать в воркере и потом получить тотал с использованием каналов, mutex или атомиков можно (в данном случае ты прав, наверное самое оптимальное решение будет с использованием канала).
Наверное можно собирать периодически тотал со всех воркеров(допустим раз в 10 секунд), но это уже немного другая задача


if atomic.CompareAndSwapUint64(addr, cur, nxt) {
return nxt
}

Реализация с циклом for похожа на принцип работы мьютекса, поэтому производительность будет одинаковая, а в некоторых моментах даже хуже (т.к. циклы в lockSlow() и unlockSlow() написаны на более низком уровне)

Имхо, в вашем примере прирост скорости вышел только из-за работы шедулера горутин, поэтому на других устройствах результаты будут совершенно другими.

Вывод: ждем 1.19

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации