आज मैंने std::vector
और std::array
की जीसीसी अनुकूलन में कुछ मतभेदों की तुलना करने और तुलना करने का निर्णय लिया। आम तौर पर, मैंने पाया कि मुझे क्या उम्मीद है: छोटे सरणी के संग्रह पर प्रत्येक कार्य करने के लिए एक संग्रह समकक्ष वैक्टर पर कार्यों को करने से कहीं अधिक तेज है।क्यों <T, N> वेक्टर <T> से धीमा हो जाएगा?
हालांकि, मैं कुछ अप्रत्याशित पाया: std::vector
का उपयोग कर सरणियों के संग्रह को स्टोर करने के तेजीstd::array
का उपयोग करने से है। बस अगर यह ढेर पर बड़ी मात्रा में डेटा के कुछ आर्टिफैक्ट का परिणाम था, तो मैंने ढेर पर एक सरणी के रूप में आवंटित करने की कोशिश की और ढेर पर सी-स्टाइल सरणी में (लेकिन परिणाम अभी भी एक सरणी जैसा दिखता है ढेर पर सरणी और सरणी के वेक्टर)।
किसी भी विचार क्यों std::vector
होगा कभी मात std::array
(जिस पर संकलक अधिक संकलन समय की जानकारी है)?
मैंने gcc-4.7 -std=c++11 -O3
(gcc-4.6 -std=c++0x -O3
का उपयोग करके संकलित इस परिणाम में भी होना चाहिए)। रनटाइम की गणना bash
-native time
कमांड (उपयोगकर्ता समय) का उपयोग करके की गई थी।
कोड:
#include <array>
#include <vector>
#include <iostream>
#include <assert.h>
#include <algorithm>
template <typename VEC>
double fast_sq_dist(const VEC & lhs, const VEC & rhs) {
assert(lhs.size() == rhs.size());
double result = 0.0;
for (int k=0; k<lhs.size(); ++k) {
double tmp = lhs[k] - rhs[k];
result += tmp * tmp;
}
return result;
}
int main() {
const std::size_t K = 20000;
const std::size_t N = 4;
// declare the data structure for the collection
// (uncomment exactly one of these to time it)
// array of arrays
// runtime: 1.32s
std::array<std::array<double, N>, K > mat;
// array of arrays (allocated on the heap)
// runtime: 1.33s
// std::array<std::array<double, N>, K > & mat = *new std::array<std::array<double, N>, K >;
// C-style heap array of arrays
// runtime: 0.93s
// std::array<double, N> * mat = new std::array<double, N>[K];
// vector of arrays
// runtime: 0.93
// std::vector<std::array<double, N> > mat(K);
// vector of vectors
// runtime: 2.16s
// std::vector<std::vector<double> > mat(K, std::vector<double>(N));
// fill the collection with some arbitrary values
for (std::size_t k=0; k<K; ++k) {
for (std::size_t j=0; j<N; ++j)
mat[k][j] = k*N+j;
}
std::cerr << "constructed" << std::endl;
// compute the sum of all pairwise distances in the collection
double tot = 0.0;
for (std::size_t j=0; j<K; ++j) {
for (std::size_t k=0; k<K; ++k)
tot += fast_sq_dist(mat[j], mat[k]);
}
std::cout << tot << std::endl;
return 0;
}
नायब 1: सभी संस्करणों एक ही परिणाम मुद्रित करें।
एनबी 2: और बस प्रदर्शित करने के लिए है कि दोनों के बीच मतभेद क्रम std::array<std::array<double, N>, K>
, std::vector<std::array<double, N> >
, और std::vector<std::vector<double> >
था नहीं बस काम/प्रारंभ से जब आवंटन, बस (यानी गणना और मुद्रण बाहर टिप्पणी संग्रह आवंटन की runtimes tot
) क्रमशः 0.000s, 0.000s और 0.004s थे।
एनबी 3: कैशिंग में अनुचित मतभेदों को रोकने के लिए प्रत्येक विधि को संकलित और अलग-अलग चलाया जाता है (उसी निष्पादन योग्य के भीतर बैक-टू-बैक नहीं)।
नायब 4: सरणियों की सरणी के लिए
विधानसभा: http://ideone.com/SM8dB
सरणियों के वेक्टर के लिए विधानसभा: http://ideone.com/vhpJv
वैक्टर की वेक्टर के लिए विधानसभा: बस बिल्कुल स्पष्ट होना: http://ideone.com/RZTNE
नायब 5 , मैं एसटीएल की आलोचना करने का इरादा नहीं रख रहा हूं। एक बिल्कुल प्यार एसटीएल और, न केवल मैं इसे अक्सर उपयोग करता हूं, प्रभावी उपयोग के विवरण ने मुझे सी ++ की बहुत सूक्ष्म और महान विशेषताएं सिखाई हैं। इसके बजाए, यह एक बौद्धिक पीछा है: मैं कुशल सी ++ डिज़ाइन के सिद्धांतों को जानने के लिए बस समय-समय पर चीजें कर रहा था।
इसके अलावा, यह, एसटीएल इसके लिए जिम्मेदार अस्वस्थ होगा क्योंकि यह क्रम अंतर के एटियलजि deconvolve के लिए मुश्किल है: अनुकूलन के चालू रहते हुए, यह संकलक अनुकूलन है कि यह तेज बजाय कोड को धीमा से हो सकता है।अनुकूलन बंद होने के साथ, यह अनावश्यक प्रतिलिपि संचालन से हो सकता है (जिसे अनुकूलित किया जाएगा और कभी भी उत्पादन कोड में निष्पादित नहीं किया जाएगा), जिसे कुछ डेटा प्रकारों के मुकाबले दूसरों के मुकाबले पक्षपातपूर्ण किया जा सकता है।
यदि आप मेरे जैसे उत्सुक हैं, तो मुझे आपकी मदद करने में आपकी मदद पसंद आएगी।
अधिक सटीक मान देखने के लिए इसे 1000 की पुनरावृत्ति गणना के साथ चलाने का प्रयास करें। वे दिखते हैं कि वे विलंबता मूल्य हो सकते हैं। –
@ कोलेजोहनसन क्या आपका मतलब 'एन = 1000' या' के = 1000' है? यदि आपका मतलब 'एन = 1000' है, तो सरणी का वेक्टर लगभग वैक्टरों के वेक्टर के समान होता है (क्योंकि लूप को अनलोल करने का ओवरहेड बहुत अधिक होता है)। 'एन = 1' का उपयोग वेक्टर के वेक्टर और वेक्टर के वेक्टर के बीच बहुत अधिक अंतर में होता है, क्योंकि सरणी के वेक्टर को अनिवार्य रूप से डबल के वेक्टर में परिवर्तित किया जाना चाहिए। इसलिए सरणी और सरणी के वेक्टर की सरणी की तुलना करने का सबसे दिलचस्प मामला 'के << एन' (' << 'गणित के अर्थ में, बिट शिफ्ट भावना नहीं है)। – user
यदि आप दो परीक्षणों को स्वैप करते हैं तो क्या होता है? – Mehrdad