2009-10-12 7 views
7

Я использую общие указатели для времени времени, и у меня есть проблемы с производительностью в моей программе ... Поэтому я хотел бы знать, приведет ли общий указатель к снижению производительности. Если да, то как тяжело? Большое спасибо.Общие указатели и производительность

Моя программа многопоточная, используя станд :: tr1 :: shared_ptr

+6

Хех. Здесь нет ответа, но мне просто нравилось, как заголовок был сформулирован. Я представляю, как процессор весело выполняет инструкции, когда вдруг видит, что команда общего указателя вводит конец конвейера. «О нет, это будет huuuuurt ...... OW!» –

+0

Что заставляет вас думать, что проблема заключается в общих указателях? –

+0

Наличие людей, говорящих, что они тратят время процессора, вот оно: P – Guest

ответ

4

Общие указатели подсчет ссылок. В частности, когда вы используете многопоточность, увеличение и уменьшение счетчика ссылок может занять значительное количество времени. Причина многопоточности здесь в том, что , если вы передали общий указатель между потоками, счетчик ссылок будет разделен между этими потоками, поэтому любые манипуляции должны быть синхронизированы между потоками. Это может немного замедлить работу.

Редактировать: Для тех, кто заботится о том, насколько медленная блокировка потоков может выполнять некоторые довольно простые операции, см. Тестирование Herb Sutter с несколькими реализациями CoW Strings. Хотя его тестирование далека от совершенства (например, он тестировался только в Windows), он все же дает некоторое представление о том, какое замедление вы можете ожидать. Для большинства практических целей вы можете/могли бы думать о строке CoW как о чем-то вроде shared_ptr<charT>, с множеством (несущественных) функций-членов.

+0

Это справедливо только в том случае, если вы используете механизм подсчета ссылок, который поддерживает поток. Похоже, что это не так, согласно документации http://www.boost.org/doc/libs/1_38_0/libs/smart_ptr/shared_ptr.htm#ThreadSafety – JaredPar

+2

Он не говорит, что использует shared_ptr. Некоторые из них уже осведомлены о потоке, а некоторые нет. Можно сомневаться, является ли тот, который он использует, или нет. Тем не менее, вы, безусловно, были правы в том, что вероятность того, что это является причиной проблемы с производительностью, довольно далека. –

+0

Добавлено больше информации – Guest

10

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

Это, как говорится, очень маловероятно, что shared_ptr вызывает замедление. Тип shared_ptr и многие ранние домашние варианты используются во все большем количестве программ на C++. Я сам использую их в своей работе (профессионал дома). Я потратил много времени на профилирование своих рабочих приложений, а shared_ptr никогда не был даже близко к проблеме в моем коде или любом другом коде, запущенном в приложении. Скорее всего, ошибка в другом месте.

3

Очень маловероятно - вам придется тратить большую часть своего времени на прохождение указателей.

Эффект общих ptrs, как правило, незначительный, и сложно даже построить кромку края, где они становятся проблемой (предполагая правильную реализацию и правильно оптимизирующий компилятор).

Воздействие совместно PTR:

  • увеличен размер выделения.
    Это имеет значение только в том случае, если у вас много общих указателей на очень мелкие объекты (скажем, десятки миллионов shared_ptr<int>) и/или работают близко к пределу памяти. Там в небольшой потенциал для заметного снижения производительности, если дополнительные распределения превышает уровень кэша/NUMA в пределах внутреннего контура

  • увеличение NUMER распределений
    shared_ptr allcoates объект слежения (счетчик ссылок, слабый граф и DeleteR) , Это оказывает давление на кучу и может вызвать общее замедление, если у вас есть большое общее количество распределений и освобождение.
    можно избежать с помощью make_shared, помещая референта и trackng объекта в единое распределение

  • подсчет ссылок
    увеличивает стоимость копии указателя. В однопоточном приложении вы заметили, что в любом случае вы тратите много времени на копирование указателей. В многопоточном приложении вам все равно нужно иметь высокий конфликт по тем же указателям.
    Стоимость копирования может быть сохранена во многих местах, передав shared_ptr<T> const &, например. как аргумент функции.

  • разыменование
    Дополнительные расходы разыменования равны нуль в снимаемой сборке оптимизирующего компилятора. Отладочные сборки часто приравниваются к вызовам функций и дополнительным проверкам NULL. Тем не менее, особенно в сборках отладки, вам придется потратить большую часть времени на указатели разыменования, чтобы это изменило ситуацию.


Без дополнительной informaiton, мы не можем вам помочь. Вам нужно описать, что такое «проблемы с производительностью» (общая неаккуратность, определенные операции, длительное время, много обмена) и некоторые ключевые показатели - то, что делает ваше приложение, сколько у них умных указателей, как часто они копируются, и какие другие операции вы запускаете, бесцельно манипулируя умными указателями.

Или вы научитесь использовать монитор производительности и/или профилировщик, чтобы выяснить, что вызывает замедление, и если есть особые узкие места.

5

Если ваша программа, похоже, имеет проблемы с производительностью, совершенно естественно начинать угадывать, что может быть проблемой, но если вы хотите сделать ставку, она почти на 100% скорее всего будет чем-то другим. Профилирование может найти проблему. This is the method I use.

0

Одна вещь, которая может повредить производительность, является чрезмерной передачей shared_ptr в качестве параметров функции. Решение для этого будет передавать ссылки на shared_ptr. Однако, это микро-оптимизации, поэтому сделать это только когда это действительно необходимо

редактировать: Когда вы думаете об этом, есть лучшие способы оптимизации:

  • При чрезмерном прохождении указателя, вероятно, вы должны позволить объект что-то делает, а не перетаскивает его.
  • Вы можете передать (константную) ссылку на объект вместо указателя
  • передать ссылку на указатель, когда указатель должен быть изменен
0

Не раздумывайте о производительности: Profile коде.

12

Если ваше приложение передает около 700-байтовые XML-сообщения, которые могут содержаться в сообщениях протокола по протоколу 64 байта или сообщениях с ASB-сообщением по 85 байт, это, вероятно, не имеет значения. Но если он обрабатывает миллион штук в секунду, я бы не отказался от стоимости добавления двух полных циклов read write write (RMW) к прохождению указателя.

Полностью прочитанный вариант изменения записи составляет порядка 50 нс, а два - 100 нс. Эта стоимость представляет собой стоимость блокировки и блокировки-dec - то же, что и 2 CAS. Это половина резерва и освобождения от критического раздела Windows.Это сравнивается с одним нажатием одного машинного цикла (400 секунд PICO на машине 2,5 ГГц)

И это даже не включает другие затраты на аннулирование строки кэша, которая фактически содержит счет, последствия блокировки BUS на других процессорах и т. д. и т. д.

Передача интеллектуальных указателей по ссылке const почти всегда ВСЕГДА. Если вызываемый пользователь не создает новый общий указатель, когда он хочет гарантировать или контролировать время жизни получателя , то это ошибка в вызываемом абоненте. Чтобы волей-неволей передавать потоки, безопасные ссылки, считающие интеллектуальные указатели вокруг значения, просто требуют получения производительности.

Использование ссылочных счетных указателей упрощает жизнь, без сомнения, но передавать общие указатели по достоинству, чтобы попытаться защитить от дефектов в вызываемой стороне, является чистой и полной бессмыслицей.

Чрезмерное использование подсчета ссылок может в короткий срок превратить небольшую программу, которая может обрабатывать 1 мм сообщений в секунду (м/с) в жирную, которая обрабатывает 150 тыс. М/с на одном и том же оборудовании. Внезапно вам понадобится половина стойки серверов и 10000 долларов в год на электричестве.

Вам всегда лучше, если вы можете управлять временем жизни объектов без подсчета ссылок.

Примером простого улучшения можно сказать, что если вы собираетесь разветвлять объект, и вы знаете, что ширина разветвления (скажем n) увеличивается на n, а индивидуально увеличивается на каждом разветвлении.

BTW, когда процессор видит префикс блокировки, он действительно говорит: «О нет, это будет больно».

Все, что касается меня, я согласен со всеми, что вы должны проверить горячую точку.

Смежные вопросы