Не могли бы вы помочь выяснить, в чем причина постоянного снижения производительности кода ниже. Если вы запустите код, вы увидите, что он печатает количество итераций в секунду. Через 10-15 секунд количество итераций в секунду в 2 раза меньше, чем в начале. Сначала проблема возникла в QT, но я переделал код, чтобы проверить его с помощью std, и проблема воспроизводится.
#include <iostream>
#include <vector>
#include <memory>
#include <string>
#include <chrono>
using namespace std;
int64_t GetUsecTime()
{
return std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now()).time_since_epoch().count();
}
namespace IType {
enum T {
oI = 0,
oI_2 = 1,
};
}
class BaseClass
{
public:
BaseClass(IType::T t)
: m_type(t)
{}
virtual ~BaseClass() {}
IType::T type()
{
return m_type;
}
private:
IType::T m_type;
};
class InheritedClass : public BaseClass
{
public:
static shared_ptr<InheritedClass> CreateShared(const string& some)
{
//return shared_ptr<InheritedClass>(new InheritedClass(some));
return make_shared<InheritedClass>(some);
}
static shared_ptr<InheritedClass> CreateShared()
{
//return shared_ptr<InheritedClass>(new InheritedClass(some));
return make_shared<InheritedClass>();
}
InheritedClass(const string& some)
: BaseClass(IType::oI)
, someFiled(some)
{}
InheritedClass()
: BaseClass(IType::oI)
, someFiled("")
{}
void setField(const string& value)
{
someFiled = value;
}
private:
string someFiled;
};
class InheritedClass_2 : public BaseClass
{
public:
static shared_ptr<InheritedClass_2> CreateShared()
{
//return shared_ptr<InheritedClass_2>(new InheritedClass_2());
return make_shared<InheritedClass_2>();
}
InheritedClass_2()
: BaseClass(IType::oI_2)
{}
void setField(int value)
{
someFiled = value;
}
private:
int someFiled;
};
class someclass
{
public:
someclass()
{
int64_t dataSize(0);
int64_t oldDataSize(0);
int64_t time0(GetUsecTime());
int64_t time(time0);
for (int i = 0; i<8000000; i++)
{
// TEST CONSTRUCTORS
//auto instance=InheritedClass::CreateShared(); // No Problem...
auto instance = InheritedClass::CreateShared(""); // PROBLEM!! With this line, speed is constantly decreasing
//TEST CODE:
//instance->setField("just something"); // PROBLEM!! With this line, speed is constantly decreasing
V.push_back(instance);
auto instance_2 = InheritedClass_2::CreateShared();
instance_2->setField(i);
V.push_back(instance_2);
dataSize = i;
if (GetUsecTime() - time > 1000000)
{
time = GetUsecTime();
cout << "Processed: " << dataSize - oldDataSize << endl;
oldDataSize = dataSize;
}
}
cout << V.size() << " in " << (GetUsecTime() - time0) / 1000.0 << " ms" << endl;
}
private:
vector<shared_ptr<BaseClass> > V;
};
int main(int argc, char *argv[])
{
someclass s;
return 0;
}
код работал в QT и Visual Studio. Распечатка из программы QT ниже (уменьшение с 220000 до 67000):
Processed: 31681
Processed: 196038
Processed: 234112
Processed: 229468
Processed: 216378
Processed: 227070
Processed: 198330
Processed: 211321
Processed: 197137
Processed: 151333
Processed: 167995
Processed: 168307
Processed: 163719
Processed: 153696
Processed: 110894
Processed: 143917
Processed: 137006
Processed: 129974
Processed: 127678
Processed: 124093
Processed: 124029
Processed: 123018
Processed: 118595
Processed: 116676
Processed: 115023
Processed: 73030
Processed: 111768
Processed: 110222
Processed: 103588
Processed: 106266
Processed: 105271
Processed: 105031
Processed: 102042
Processed: 100258
Processed: 99404
Processed: 98955
Processed: 97007
Processed: 95901
Processed: 93696
Processed: 91405
Processed: 91061
Processed: 90175
Processed: 87727
Processed: 87448
Processed: 85510
Processed: 84238
Processed: 41837
Processed: 76040
Processed: 75694
Processed: 82918
Processed: 81515
Processed: 80957
Processed: 79657
Processed: 80840
Processed: 79110
Processed: 78720
Processed: 76078
Processed: 76067
Processed: 75412
Processed: 75546
Processed: 74052
Processed: 73386
Processed: 69608
Processed: 66880
Processed: 68731
Processed: 70560
Processed: 68979
Processed: 69985
Processed: 70516
Processed: 68464
Processed: 67379
Processed: 67980
Processed: 67746
Processed: 67332
16000000 in 74537 ms
Распечатка из программы VisualSutio ниже (начальные значения меньше, менее стабильны, но не уменьшаются):
Processed: 81138
Processed: 78107
Processed: 81158
Processed: 101733
Processed: 69418
Processed: 99900
Processed: 54649
Processed: 94161
Processed: 95660
Processed: 31477
Processed: 97066
Processed: 97588
Processed: 99001
Processed: 99554
Processed: 492
Processed: 99197
Processed: 100049
Processed: 99765
Processed: 100066
Processed: 97667
Processed: 93807
Processed: 100146
Processed: 99378
Processed: 99824
Processed: 98228
Processed: 97943
Processed: 99552
Processed: 100299
Processed: 99753
Processed: 90703
Processed: 98276
Processed: 99480
Processed: 99569
Processed: 99528
Processed: 99058
Processed: 98939
Processed: 97637
Processed: 99334
Processed: 99713
Processed: 99540
Processed: 99212
Processed: 99339
Processed: 98781
Processed: 40334
Processed: 98810
Processed: 99134
Processed: 99953
Processed: 99884
Processed: 99891
Processed: 100036
Processed: 100037
Processed: 98182
Processed: 98393
Processed: 99091
Processed: 98359
Processed: 99515
Processed: 100710
Processed: 99065
Processed: 100507
Processed: 99915
Processed: 96591
Processed: 97256
Processed: 100400
Processed: 99551
Processed: 7829
Processed: 100520
Processed: 99480
Processed: 100201
Processed: 99145
Processed: 100898
Processed: 100403
Processed: 99873
Processed: 99761
Processed: 99590
Processed: 99795
Processed: 100142
Processed: 99396
Processed: 99607
Processed: 98091
Processed: 97379
Processed: 98045
Processed: 98448
Processed: 97853
Processed: 98633
Processed: 96140
16000000 in 96518.3 ms
Вы делаете довольно много ненужных копий с помощью make_shared
. make_shared<InheritedClass>(some)
и make_shared<InheritedClass_2>()
достаточно. (make_shared
не берет объект и делает его общим, он делает общий объект.)
Я играл с make_shared и просто с shared_ptr(), на саму упомянутую проблему это никак не повлияло. Тем не менее, спасибо за подсказку.
Вот мое предположение: someField
всегда будет построен по умолчанию. Я думаю, что компилятор может убрать someFiled("")
инициализацию во втором конструкторе. Но, вероятно, у него проблемы с удалением пустой строки из строки ::CreateShared("")
. И пустые строки не бесплатны, нет. Хотя это зависит от реализации, вполне вероятно, что под капотом для него выделена ненулевая память (емкость). Итак, ::CreateShared("")
в два раза тяжелее ::CreateShared()
.
Это также кажется зависимым от компилятора, см. это: godbolt.org/z/GPod3z Clang генерирует очень плохой код для проверки2. Но Gcc выдает один и тот же код для обоих.
Я понимаю все ваши ответы, но все они могут только объяснить разницу поведения на разных компиляторах. Я хотел бы попросить вас запустить код на одну минуту, и вы увидите, что выходные значения всегда будут каждый раз уменьшаться на несколько процентов. Это пока не ясно.
Я запускал код в QT и VisualStudio. Как ни странно, программа в VS работает медленнее (выходные распечатки меньше), но они не уменьшаются! На QT, как ни странно, значения более стабильны, они начинаются с большего значения, но постоянно уменьшаются. Похоже, что зависимость от уже выделенной памяти, а во-вторых, имеет какое-то отношение к внутреннему полю String в instance1. Код довольно простой, но моих знаний недостаточно, чтобы объяснить все эти хитрые вещи.
Я полагаю, это происходит из-за того, что std::vector
растет в два раза каждый раз, когда нет места для новых предметов. Когда это происходит, он копирует текущий контент в новое выделенное пространство. Когда количество элементов становится большим, это делает задержку заметной.
Также, чтобы найти строку, где больше всего тратится процессор, совершенно необходимо использовать профайлер. Другие попытки, такие как комментирование и раскомментирование части кода, не дадут точного понимания, в чем проблема и как оптимизировать.
Я пробовал list и deque, без изменений. Но я обновил сообщение темы, и Visual Studio дает другой результат (без постоянного снижения) с тем же кодом. Так что вектор, наверное, не причина, если не повод для компилятора VisualStudio? Кстати, вектор НЕ является причиной, потому что можно только закомментировать строки с пометкой //ПРОБЛЕМА, и все будет работать нормально, не тормозя.
Может быть. Чтобы узнать точно, рассмотрите возможность использования профилировщика. Это сэкономит ваше время.
@Dmitry Gorelov Комментирование и раскомментирование строк кода может иметь побочные эффекты и вызывать проблемы. Я не настаиваю на том, что это имеет место в вашем случае, но единственный способ узнать и решить это — профилировать код.
Спасибо 4xy, ищу профайлера. Тем не менее, я просто надеюсь, что код не так уж и сложен, и кто-то, кто сталкивался с подобными проблемами, мог бы дать ответ. Так что пусть вопрос останется нерешенным на пару дней.
Итак, решение:
Новая распечатка из realeas exe:
Processed: 1923592
Processed: 2062627
Processed: 1993109
Processed: 2541079
Processed: 1666522
Processed: 2562799
Processed: 1186022
Processed: 2578212
Processed: 2590275
40000000 in 9599 ms
Если вы пометите язык (я полагаю, C++), вы можете привлечь больше пользователей, которые будут полезны и разбираются в теме.