Sorunum oldukça basit, lambda'yı bir "karşılaştırıcı" olarak kullanabileceğim şekilde kullanmak istiyorum, biraz daha iyi açıklayayım. İki büyük yapılıma sahibim, her ikisi de operator<
kendi uygulamasına sahipler ve ayrıca iki yapıyı kullanan bir useless
sınıfına (bu sorunun bağlamında yalnızca sınıfın adı) sahipler, her şeye benziyor:Bir işlev nesnesi yerine lambda kullanmak, kötü performans
struct be_less
{
//A lot of stuff
int val;
be_less(int p_v):val(p_v){}
bool operator<(const be_less& p_other) const
{
return val < p_other.val;
}
};
struct be_more
{
//A lot of stuff
int val;
be_more(int p_v):val(p_v){}
bool operator<(const be_more& p_other) const
{
return val > p_other.val;
}
};
class useless
{
priority_queue<be_less> less_q;
priority_queue<be_more> more_q;
public:
useless(const vector<int>& p_data)
{
for(auto elem:p_data)
{
less_q.emplace(elem);
more_q.emplace(elem);
}
}
};
iki yapı yıllarda tekrarını kaldırmak ister whould
, simpliest fikri yapı bir şablon yapmak ve karşılaştırma işi yapmak için iki functor sağlamaktır: oldukça iyi
template<typename Comp>
struct be_all
{
//Lot of stuff, better do not duplicate
int val;
be_all(int p_v):val{p_v}{}
bool operator<(const be_all<Comp>& p_other) const
{
return Comp()(val,p_other.val);
}
};
class comp_less
{
public:
bool operator()(int p_first,
int p_second)
{
return p_first < p_second;
}
};
class comp_more
{
public:
bool operator()(int p_first,
int p_second)
{
return p_first > p_second;
}
};
typedef be_all<comp_less> all_less;
typedef be_all<comp_more> all_more;
class useless
{
priority_queue<all_less> less_q;
priority_queue<all_more> more_q;
public:
useless(const vector<int>& p_data)
{
for(auto elem:p_data)
{
less_q.emplace(elem);
more_q.emplace(elem);
}
}
};
Bu işi Şimdi, iki ek işlev nesnesinin fiyatına yapı kodunda herhangi bir çoğaltma bulunmadığından emin olun. Lütfen unutmayın ki, operator<
'un uygulanmasını çok basitleştirdiğim için, hipotetik gerçek kod sadece iki virgülü karşılaştırmaktan çok daha fazlasını yapar. Sonra
i (sadece bir deneme olarak) lambda kullanarak i uygulamak başardı hayranlarıyla tek çalışan çözüm aynı şeyi yapmak için nasıl düşünüyordum geçerli:
template<typename Comp>
struct be_all
{
int val;
function<bool(int,int)> Comparator;
be_all(Comp p_comp,int p_v):
Comparator(move(p_comp)),
val{p_v}
{}
bool operator<(const be_all& p_other) const
{
return Comparator(val, p_other.val);
}
};
auto be_less = [](int p_first,
int p_second)
{
return p_first < p_second;
};
auto be_more = [](int p_first,
int p_second)
{
return p_first > p_second;
};
typedef be_all<decltype(be_less)> all_less;
typedef be_all<decltype(be_more)> all_more;
class useless
{
priority_queue<all_less> less_q;
priority_queue<all_more> more_q;
public:
useless(const vector<int>& p_data)
{
for(auto elem:p_data)
{
less_q.emplace(be_less,elem);
more_q.emplace(be_more,elem);
}
}
};
Bu uygulama sadece yeni üye eklemek Yapısını içeren veriye, ama aynı zamanda çok zayıf bir performansa sahip olduğum için, size burada gösterdiğim işe yaramaz sınıf için bir örnek oluşturduğum küçük bir test hazırladım, her zaman 2 kg'lık bir vektörle kurucuyu besliyorum Tamsayılar, sonuçlar şu şekildedir:
- E 48 ms alır
- ikinci yararsız sınıf oluşturmak için 228ms Alır ilk işe yaramaz sınıfı (funktor)
- üçüncü yararsız sınıf oluşturmak için 557ms Alır Açıkça (lambda'lar)
i kaldırıldı bedeli yapıcısı xecute çoğaltma çok yüksek ve orijinal kodda çoğaltma hala var. Unutmayın ki, üçüncü uygulamanın performansının ne kadar kötü olduğunu, orijinalin on kat daha yavaş olduğunu, üçüncü uygulamanın nedeninin ikinci saniyeden daha yavaş olduğuna inandığımı, be_all
kurucusundaki ek parametreden kaynaklandığını ancak ...
template<typename Comp>
struct be_all
{
int val;
be_all(int p_v):val{p_v}
{}
bool operator<(const be_all& p_other) const
{
return Comp(val, p_other.val);
}
};
bool be_less = [](int p_first,
int p_second)
{
return p_first < p_second;
};
bool be_more = [](int p_first,
int p_second)
{
return p_first > p_second;
};
typedef be_all<decltype(be_less)> all_less;
typedef be_all<decltype(be_more)> all_more;
class useless
{
priority_queue<all_less> less_q;
priority_queue<all_more> more_q;
public:
useless(const vector<int>& p_data)
{
for(auto elem:p_data)
{
less_q.emplace(elem);
more_q.emplace(elem);
}
}
};
i auto
kaldırırsanız:
Aslında da hala lambda kullanılan dördüncü durumda, var ama Comparator
üyesinin ve be_all
ek parametre kurtulmak, kod şudurkullanıyorum bile lambda ve bool
yerine kod oluşturmak kullanın operator<
'da.
- 48ms: bana çok garip Ne
bu dördüncü uygulama (
Comparator
üyesi olmadan lambda) takip ediyor i kayıt başardı ortalama performans sonunda, diğerinden daha bile yavaş olmasıdır - 228ms
- 557ms
- 698ms
Neden functor Bu senaryoda lambdalardan çok daha hızlı mı? Lambda'nın sıradan bir functor kadar iyi performans göstermesini bekliyordum, birisinin yorumunu yapabilir mi lütfen? Dördüncü uygulamanın üçüncü seviyeden daha yavaş olmasının teknik bir sebebi var mı?
PS:
i kullanıyorum compilator gr ++ -o3 ile 4.8.2 olduğunu.
namespace benchmark
{
template<typename T>
long run()
{
auto start=chrono::high_resolution_clock::now();
T t(data::plenty_of_data);
auto stop=chrono::high_resolution_clock::now();
return chrono::duration_cast<chrono::milliseconds>(stop-start).count();
}
}
ve:
cout<<"Bad code: "<<benchmark::run<bad_code::useless>()<<"ms\n";
cout<<"Bad code2: "<<benchmark::run<bad_code2::useless>()<<"ms\n";
cout<<"Bad code3: "<<benchmark::run<bad_code3::useless>()<<"ms\n";
cout<<"Bad code4: "<<benchmark::run<bad_code4::useless>()<<"ms\n";
giriş tamsayılar kümesi, plenty_of_data
herkes için aynıdır benim testte ben her useless
sınıf için ben gerekli zamanı dikkate alınacak bir örnek ve kullanma kronostratigrafik oluşturmak 2 milyondan fazla tam bir vektördür. Zaman
TL; DR: Karşılaştırmalı bir functor genellikle bir ya da daha fazla 'bool operatörüne() (T, U)' 'daha az' –
'değerine sahip olduğumu değerlendirmektedir. Açıkça işaretlenmiş 4 ölçülü vakayı içeren bir kod bloğu yazdırabilir miyim, kendi derlememde tek bir kopyada yürütüp yapıştırabilir miyim? –