Как оптимизировать программу golang, которая проводит больше всего времени в runtime.osyield и runtime.usleep
Я работал над оптимизацией кода, который анализирует данные социальных графов (с большой помощью https://blog.golang.org/profiling-go-programs), и я успешно переработал много медленного кода.
Все данные загружаются в память из базы данных в первую очередь, и анализ данных оттуда оказывается связанным с процессором (максимальное потребление памяти < 10 МБ, CPU1 @ 100%)
Но сейчас большая часть времени моей программы, кажется, находится в runtime.osyield и runtime.usleep. Какой способ предотвратить это?
Я установил GOMAXPROCS=1, и код не создает никаких подпрограмм (кроме того, что могут вызывать библиотеки golang).
Это мой топ10 вывод от pprof
(pprof) top10
62550ms of 72360ms total (86.44%)
Dropped 208 nodes (cum <= 361.80ms)
Showing top 10 nodes out of 77 (cum >= 1040ms)
flat flat% sum% cum cum%
20760ms 28.69% 28.69% 20850ms 28.81% runtime.osyield
14070ms 19.44% 48.13% 14080ms 19.46% runtime.usleep
11740ms 16.22% 64.36% 23100ms 31.92% _/C_/code/sc_proto/cloudgraph.(*Graph).LeafProb
6170ms 8.53% 72.89% 6170ms 8.53% runtime.memmove
4740ms 6.55% 79.44% 10660ms 14.73% runtime.typedslicecopy
2040ms 2.82% 82.26% 2040ms 2.82% _/C_/code/sc_proto.mAvg
890ms 1.23% 83.49% 1590ms 2.20% runtime.scanobject
770ms 1.06% 84.55% 1420ms 1.96% runtime.mallocgc
760ms 1.05% 85.60% 760ms 1.05% runtime.heapBitsForObject
610ms 0.84% 86.44% 1040ms 1.44% _/C_/code/sc_proto/cloudgraph.(*Node).DeepestChildren
(pprof)
Функции _ /C_/code/sc_proto/* - мой код.
(лучше, SVG-версия графика здесь: https://goo.gl/Tyc6X4)
1 ответ
Я нашел ответ сам, поэтому я выкладываю это здесь для всех, у кого есть подобная проблема. И отдельное спасибо @JimB за то, что отправили меня по правильному пути.
Как видно из графика, пути, ведущие к osyield и usleep, являются процедурами сборки мусора. Эта программа использовала связанный список, который генерировал много указателей, которые создавали большую работу для gc, которая иногда блокировала выполнение моего кода, пока он очищал мой беспорядок.
В конечном итоге решение этой проблемы появилось на https://software.intel.com/en-us/blogs/2014/05/10/debugging-performance-issues-in-go-programs (кстати, это был потрясающий ресурс). Я следовал инструкциям о профилировщике памяти там; и рекомендация заменить наборы указателей на кусочки прояснила мои проблемы с сборкой мусора, и мой код теперь стал намного быстрее!