Как оптимизировать программу 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 (кстати, это был потрясающий ресурс). Я следовал инструкциям о профилировщике памяти там; и рекомендация заменить наборы указателей на кусочки прояснила мои проблемы с сборкой мусора, и мой код теперь стал намного быстрее!

Другие вопросы по тегам