Игорь прав: пусть один поток делает все, что пишет лог. Имейте в виду, что ядро должно выполнять блокировку для синхронизации доступа к дескриптору открытого файла (который отслеживает положение файла), поэтому, выполняя запись из нескольких ядер, вы вызываете конкуренцию внутри ядра. Хуже того, вы выполняете системные вызовы из нескольких ядер, а это означает, что доступ к коду/данным ядра загрязнит ваши кеши на нескольких ядрах.
Дополнительную информацию о влиянии создания системные вызовы производительности кода пользовательского пространства после завершения системного вызова. (И про промахи кеша данных/инструкций внутри ядра при нечастых системных вызовах). Определенно имеет смысл иметь один поток, выполняющий все системные вызовы, по крайней мере, все системные вызовы записи, чтобы изолировать эту часть вашего процесса от одного ядра. А также конфликт блокировок внутри ядра.
В этом документе FlexSC рассказывается об идее группирования системных вызовов для уменьшения переходов пользователь->ядро->пользователь, но они также измеряют накладные расходы для обычного метода синхронного системного вызова. Более важным является обсуждение загрязнения кеша системными вызовами.
В качестве альтернативы, если вы можете позволить нескольким потокам записывать в ваш файл журнала, вы можете просто сделать это и вообще не использовать очередь.
Не гарантируется, что большая запись будет завершена без перерыва, но запись малого и среднего размера должна (почти?) всегда копировать весь свой буфер в большинстве ОС. Особенно, если вы пишете в файл, а не в канал. IDK, как Linux write() ведет себя, когда он вытеснен, но я ожидаю, что он обычно возобновляет запись, а не возвращает, не записав все запрошенные байты. Частичная запись может быть более вероятной, когда прерывается сигналом.
Гарантируется, что байты от двух системных вызовов write()
не будут перемешаны; все байты из одного будут до или после байтов из другого. Однако вы правы в том, что частичная запись является потенциальной проблемой. Я забыл, возобновит ли оболочка системного вызова glibc вызов для вас на EINTR
. Хотя в этом случае это означает, что на самом деле не было записано ни одного байта, иначе он вернул бы успех с подсчетом байтов.
Вы должны проверить это на частичную запись и на производительность. Блокировка в пространстве ядра может быть дешевле, чем накладные расходы вашей свободной от блокировок очереди, но выполнение системных вызовов из каждого потока, генерирующего сообщения журнала, может снизить производительность. (И когда вы тестируете это, убедитесь, что вы делаете это с какой-то реальной работой, происходящей в вашем пользовательском пространстве, а не просто с циклом, который только вызывает запись.)
person
Peter Cordes
schedule
27.08.2016