J. Bravo: Глянул в спеку, действительно: "If no Accept-Encoding field is present in a request, the server MAY assume that the client will accept any content coding.". Тогда попробуйте указать заголовок Accept-Encoding: identity . Тут уж Вам по rfc не должны отказывать.
J. Bravo, для простоты можно еще удостовериться, что в заголовках не передается Accept-Encoding параметр. Сервер тогда не должен применять gzip и будет отдавать нормальную страницу.
andreyvlru: вообще должен, так как на одном большом файле скорости передачи есть куда "разогнаться", в отличии от кучи мелких файлов. Другой вопрос, что требуется дополнительное место, что не всегда вариант. Ну и я не уверен в том, насколько лучше станет.
Армянское Радио: можно написать тесты и для синхронизации, можно и для проверки на утечку ресурсов. Было бы желание/фантазия/время/ресурсы. Также не катит вариант, когда проект уже есть и архитектура у него плохо тестируемая и переписывать ради тестов проект никто не будет, или, возможно, платформа как-то ограничивает.
Написание тестов не отменяет детальное логгирование и все вышеуказанные советы, разумеется. Не панацея, не серебренная пуля. Но если они есть, и пишутся, и поддерживаются, то это +100500 к предсказуемости, уверенности в коде и painless дебаге, так как многие ситуации гораздо легче смоделировать.
uvelichitel, neolink
Сделал небольшой бенчмарк play.golang.org/p/LUD4idmK0D .
Онлайн не работает, платформа режет. Скопируйте в локальный файл и через go run.
У меня стандартный вариант через < 0 работает чуть-чуть быстрее. Платформа darwin/amd64.
Benchmark of AbsStd():
2000000000 0.68 ns/op 0 B/op 0 allocs/op
Benchmark of AbsMagic():
2000000000 0.70 ns/op 0 B/op 0 allocs/op
Отрыв варьируется от 0 до 0.03 ns/op.
SilentFl, Виталий Яковенко, все понял, благодарю за пояснение. Я как-то банально не заметил close() в примерах выше, потому мой мир и пошатнулся. Теперь картинка встала на место.
SilentFl: кстати, странно...чего-то я перестал понимать. Разве главная горутина не должна заблокироваться, когда вычитает все значения?
В спецификации четко написано:
If the capacity is zero or absent, the channel is unbuffered and communication succeeds only when both a sender and receiver are ready. Otherwise, the channel is buffered and communication succeeds without blocking if the buffer is not full (sends) or not empty (receives).
Виталий Яковенко: Что-то я погорячился, каюсь. С sync.Once все в порядке, если операцию запроса к бэкенду не пихать sync.Once, а оставить там только отправку в канал. Тем не менее, схема замечательно реализуется без sync тоже.
Виталий Яковенко: Не уверен, что это то, что нужно. В приведенном примере не происходит гонки в полном смысле этого слова. Внутренность за счет sync.Once выполняется не более одного раза. Если таковы требования, зачем тогда вообще городить каналы тут? Достаточно просто записать операции последовательно.
Насколько я понял, изначально нужно чтобы все 30 функций отработали, но Вы забрали результат только самой быстрой. В реальности, это, например, запрос на чтение к различным бэкендам, когда нас интересует получить ответ как можно быстрее от любого из них. C sync.Once() у Вас будет запрос строго к одному бэкенду, что ничем не отличается от последовательного кода.
В Вашем случае Вы пытаетесь реализовать стандартный паттерн moving on. Его реализация замечательно описана в приведенной мной статье из блога Go. Идея его проста: имеем буферизированный канал размера 1. Все горутины осуществляют туда неблокируемую запись (select с default), за счет этого туда запишется самое первое значение, а другие горутины не заблокируются, а выпадут в секцию default и завершатся. Потом в главной горутине Вы просто забираете свое значение. Всё. Даже если Вы заберете значение с главной горутины, а потом туда еще какая-то рутина успеет записать новое значение, то ничего страшного - Вы свое самое первое значение получили, а при выходе из scope все остальные данные умрут.