Saya selalu berpikir itu adalah kebijaksanaan umum yang std::vector
"diimplementasikan sebagai sebuah array," bla bla bla. Hari ini saya turun dan mengujinya, dan tampaknya tidak begitu:
Inilah beberapa hasil tes:
UseArray completed in 2.619 seconds
UseVector completed in 9.284 seconds
UseVectorPushBack completed in 14.669 seconds
The whole thing completed in 26.591 seconds
Itu sekitar 3 - 4 kali lebih lambat! Tidak benar-benar membenarkan untuk vector
komentar " mungkin lebih lambat untuk beberapa nanosec".
Dan kode yang saya gunakan:
#include <cstdlib>
#include <vector>
#include <iostream>
#include <string>
#include <boost/date_time/posix_time/ptime.hpp>
#include <boost/date_time/microsec_time_clock.hpp>
class TestTimer
{
public:
TestTimer(const std::string & name) : name(name),
start(boost::date_time::microsec_clock<boost::posix_time::ptime>::local_time())
{
}
~TestTimer()
{
using namespace std;
using namespace boost;
posix_time::ptime now(date_time::microsec_clock<posix_time::ptime>::local_time());
posix_time::time_duration d = now - start;
cout << name << " completed in " << d.total_milliseconds() / 1000.0 <<
" seconds" << endl;
}
private:
std::string name;
boost::posix_time::ptime start;
};
struct Pixel
{
Pixel()
{
}
Pixel(unsigned char r, unsigned char g, unsigned char b) : r(r), g(g), b(b)
{
}
unsigned char r, g, b;
};
void UseVector()
{
TestTimer t("UseVector");
for(int i = 0; i < 1000; ++i)
{
int dimension = 999;
std::vector<Pixel> pixels;
pixels.resize(dimension * dimension);
for(int i = 0; i < dimension * dimension; ++i)
{
pixels[i].r = 255;
pixels[i].g = 0;
pixels[i].b = 0;
}
}
}
void UseVectorPushBack()
{
TestTimer t("UseVectorPushBack");
for(int i = 0; i < 1000; ++i)
{
int dimension = 999;
std::vector<Pixel> pixels;
pixels.reserve(dimension * dimension);
for(int i = 0; i < dimension * dimension; ++i)
pixels.push_back(Pixel(255, 0, 0));
}
}
void UseArray()
{
TestTimer t("UseArray");
for(int i = 0; i < 1000; ++i)
{
int dimension = 999;
Pixel * pixels = (Pixel *)malloc(sizeof(Pixel) * dimension * dimension);
for(int i = 0 ; i < dimension * dimension; ++i)
{
pixels[i].r = 255;
pixels[i].g = 0;
pixels[i].b = 0;
}
free(pixels);
}
}
int main()
{
TestTimer t1("The whole thing");
UseArray();
UseVector();
UseVectorPushBack();
return 0;
}
Apakah saya melakukan kesalahan atau sesuatu? Atau apakah saya baru saja merusak mitos kinerja ini?
Saya menggunakan mode Rilis di Visual Studio 2005 .
Dalam Visual C ++ , #define _SECURE_SCL 0
kurangi UseVector
setengahnya (turun menjadi 4 detik). Ini sangat besar, IMO.
vector
adalah array yang dapat diubah ukurannya untuk tujuan umum. Selamat. Seperti halnya semua alat tujuan umum, dimungkinkan untuk membuat situasi khusus yang tidak optimal. Itulah sebabnya kebijaksanaan konvensional adalah memulai denganvector
dan mempertimbangkan alternatif jika perlu.Jawaban:
Menggunakan yang berikut ini:
Jadi array dua kali lebih cepat dari vektor.
Tetapi setelah melihat kode secara lebih rinci ini diharapkan; saat Anda menjalankan melintasi vektor dua kali dan array hanya sekali. Catatan: saat Anda
resize()
vektor, Anda tidak hanya mengalokasikan memori tetapi juga menjalankan vektor dan memanggil konstruktor pada setiap anggota.Menyusun ulang kode sedikit sehingga vektor hanya menginisialisasi setiap objek sekali:
Sekarang lakukan pengaturan yang sama lagi:
Vektor sekarang kinerja hanya sedikit lebih buruk daripada array. IMO perbedaan ini tidak signifikan dan dapat disebabkan oleh banyak hal yang tidak terkait dengan tes.
Saya juga akan mempertimbangkan bahwa Anda tidak menginisialisasi dengan benar / Menghancurkan objek Pixel dalam
UseArrray()
metode karena konstruktor / destruktor tidak dipanggil (ini mungkin bukan masalah untuk kelas sederhana ini tetapi sesuatu yang sedikit lebih kompleks (yaitu dengan pointer atau anggota dengan pointer) akan menyebabkan masalah.sumber
reserve()
bukanresize()
. Ini mengalokasikan ruang untuk objek (yaitu, ia mengubah kapasitas vektor) tetapi tidak membuat objek (yaitu, ukuran vektor dibiarkan tidak berubah).resize()
denganreserve()
, karena ini tidak menyesuaikan ide internal vektor dari ukurannya sendiri, sehingga penulisan selanjutnya pada elemen-elemennya secara teknis "menulis melewati akhir" dan akan menghasilkan UB. Meskipun dalam praktiknya setiap implementasi STL akan "berperilaku sendiri" dalam hal itu, bagaimana Anda mensinkronisasi ulang ukuran vektor? Jika Anda mencoba memanggilresize()
setelah mengisi vektor, itu sangat mungkin akan menimpa semua elemen dengan nilai-nilai yang dibangun secara default!reserve
hanya mengubah kapasitas vektor, bukan ukurannya./EHsc
ke switch kompilasi membersihkan itu, danassign()
benar - benar mengalahkan array sekarang. Yay.Pertanyaan yang bagus Saya datang ke sini berharap untuk menemukan beberapa perbaikan sederhana yang akan mempercepat tes vektor. Itu tidak berhasil seperti yang saya harapkan!
Optimalisasi membantu, tetapi itu tidak cukup. Dengan optimasi pada Saya masih melihat perbedaan kinerja 2X antara UseArray dan UseVector. Menariknya, UseVector secara signifikan lebih lambat daripada UseVectorPushBack tanpa optimasi.
Ide # 1 - Gunakan [] baru alih-alih malloc
Saya mencoba mengubah
malloc()
kenew[]
dalam UseArray sehingga objek akan dibangun. Dan berubah dari penugasan bidang individual ke menetapkan contoh Pixel. Oh, dan mengganti nama variabel loop dalam menjadij
.Anehnya (bagi saya), tidak ada perubahan yang membuat perbedaan apa pun. Bahkan perubahan
new[]
yang akan membangun semua Pixel secara default. Tampaknya gcc dapat mengoptimalkan panggilan konstruktor default saat menggunakannew[]
, tetapi tidak saat menggunakanvector
.Ide # 2 - Hapus panggilan operator yang berulang]
Saya juga berusaha untuk menyingkirkan
operator[]
pencarian tiga dan cache referensipixels[j]
. Itu benar-benar memperlambat UseVector! Ups.Ide # 3 - Hapus konstruktor
Bagaimana dengan menghapus konstruktor sepenuhnya? Maka mungkin gcc dapat mengoptimalkan pembangunan semua objek ketika vektor dibuat. Apa yang terjadi jika kami mengubah Pixel ke:
Hasil: sekitar 10% lebih cepat. Masih lebih lambat dari sebuah array. Hm
Ide # 4 - Gunakan iterator sebagai ganti loop index
Bagaimana kalau menggunakan
vector<Pixel>::iterator
indeks loop bukan?Hasil:
Tidak, tidak berbeda. Setidaknya itu tidak lebih lambat. Saya pikir ini akan memiliki kinerja yang mirip dengan # 2 di mana saya menggunakan
Pixel&
referensi.Kesimpulan
Bahkan jika beberapa cookie pintar mengetahui cara membuat loop vektor secepat array satu, ini tidak berbicara dengan baik tentang perilaku default
std::vector
. Begitu banyak untuk kompiler menjadi cukup pintar untuk mengoptimalkan semua C ++ ness dan membuat wadah STL secepat array mentah.Intinya adalah bahwa kompiler tidak dapat mengoptimalkan panggilan konstruktor default no-op saat menggunakan
std::vector
. Jika Anda menggunakan polosnew[]
itu mengoptimalkan mereka dengan baik. Tapi tidak denganstd::vector
. Bahkan jika Anda dapat menulis ulang kode Anda untuk menghilangkan panggilan konstruktor yang terbang di hadapan mantra di sekitar sini: "Kompiler lebih pintar daripada Anda. STL sama cepatnya seperti biasa C. Jangan khawatir tentang hal itu."sumber
vector<int>
.Ini adalah pertanyaan lama tetapi populer.
Pada titik ini, banyak programmer akan bekerja di C ++ 11. Dan dalam C ++ 11 kode OP seperti yang ditulis berjalan sama cepat untuk
UseArray
atauUseVector
.Masalah mendasar adalah bahwa sementara
Pixel
struktur Anda tidak diinisialisasi,std::vector<T>::resize( size_t, T const&=T() )
mengambil standar dibangunPixel
dan menyalinnya . Kompiler tidak menyadari bahwa ia diminta untuk menyalin data yang tidak diinisialisasi, sehingga ia benar-benar melakukan penyalinan.Di C ++ 11,
std::vector<T>::resize
memiliki dua kelebihan. Yang pertama adalahstd::vector<T>::resize(size_t)
, yang lainnya adalahstd::vector<T>::resize(size_t, T const&)
. Ini berarti ketika Anda memanggilresize
tanpa argumen kedua, itu hanya membangun default, dan kompiler cukup pintar untuk menyadari bahwa konstruksi default tidak melakukan apa-apa, sehingga ia melewatkan pass over buffer.(Dua kelebihan beban di mana ditambahkan untuk menangani jenis bergerak, dapat dibangun dan tidak dapat disalin - peningkatan kinerja ketika bekerja pada data yang tidak diinisialisasi adalah bonus).
The
push_back
solusi juga melakukan pengecekan fencepost, yang memperlambat ke bawah, sehingga tetap lebih lambat darimalloc
versi.contoh hidup (saya juga mengganti timer dengan
chrono::high_resolution_clock
).Perhatikan bahwa jika Anda memiliki struktur yang biasanya memerlukan inisialisasi, tetapi Anda ingin menanganinya setelah menambah buffer, Anda dapat melakukan ini dengan
std::vector
pengalokasi khusus . Jika Anda ingin kemudian memindahkannya ke yang lebih normalstd::vector
, saya percaya penggunaanallocator_traits
dan pengesampingan yang hati-hati==
mungkin berhasil, tetapi tidak yakin.sumber
emplace_back
vs dipush_back
sini.clang++ -std=c++11 -O3
telahUseArray completed in 2.02e-07 seconds
danUseVector completed in 1.3026 seconds
. Saya juga menambahkanUseVectorEmplaceBack
versi yang kira-kira. 2.5x secepatUseVectorPushBack
.Agar adil, Anda tidak dapat membandingkan implementasi C ++ dengan implementasi C, seperti yang saya sebut versi malloc Anda. malloc tidak membuat objek - hanya mengalokasikan memori mentah. Bahwa Anda kemudian memperlakukan memori itu sebagai objek tanpa memanggil konstruktor miskin C ++ (mungkin tidak valid - saya akan menyerahkannya kepada pengacara bahasa).
Yang mengatakan, hanya mengubah malloc ke
new Pixel[dimensions*dimensions]
dan bebas untukdelete [] pixels
tidak membuat banyak perbedaan dengan implementasi sederhana dari Pixel yang Anda miliki. Inilah hasil pada kotak saya (E6600, 64-bit):Tetapi dengan sedikit perubahan, tabel berubah:
Pixel.h
Pixel.cc
main.cc
Dikompilasi dengan cara ini:
kami mendapatkan hasil yang sangat berbeda:
Dengan konstruktor non-inline untuk Pixel, std :: vector sekarang mengalahkan array mentah.
Akan terlihat bahwa kompleksitas alokasi melalui std :: vector dan std: dialokasikan terlalu banyak untuk dioptimalkan seefektif yang sederhana
new Pixel[n]
. Namun, kita dapat melihat bahwa masalahnya hanya dengan alokasi bukan akses vektor dengan mengubah beberapa fungsi tes untuk membuat vektor / array sekali dengan memindahkannya di luar loop:dan
Kami mendapatkan hasil ini sekarang:
Apa yang dapat kita pelajari dari ini adalah std :: vector sebanding dengan array mentah untuk akses, tetapi jika Anda perlu membuat dan menghapus vektor / array berkali-kali, membuat objek yang kompleks akan lebih memakan waktu yang membuat array sederhana ketika konstruktor elemen tidak digarisbawahi. Saya tidak berpikir ini sangat mengejutkan.
sumber
Coba dengan ini:
Saya mendapatkan kinerja yang hampir sama persis dengan array.
Masalahnya
vector
adalah bahwa ini adalah alat yang jauh lebih umum daripada sebuah array. Dan itu berarti Anda harus mempertimbangkan bagaimana Anda menggunakannya. Ia dapat digunakan dalam banyak cara berbeda, menyediakan fungsionalitas yang bahkan tidak dimiliki array. Dan jika Anda menggunakannya "salah" untuk tujuan Anda, Anda mengalami banyak overhead, tetapi jika Anda menggunakannya dengan benar, biasanya pada dasarnya struktur data zero-overhead. Dalam kasus ini, masalahnya adalah Anda secara terpisah menginisialisasi vektor (menyebabkan semua elemen meminta ctor defaultnya), dan kemudian menimpa setiap elemen secara individual dengan nilai yang benar. Itu jauh lebih sulit bagi kompiler untuk mengoptimalkan jauh daripada ketika Anda melakukan hal yang sama dengan array. Itulah sebabnya vektor menyediakan konstruktor yang memungkinkan Anda melakukan hal itu:N
X
.Dan saat Anda menggunakannya, vektornya sama cepatnya dengan sebuah array.
Jadi tidak, Anda belum merusak mitos kinerja. Tetapi Anda telah menunjukkan bahwa itu hanya benar jika Anda menggunakan vektor secara optimal, yang merupakan poin yang cukup bagus juga. :)
Sisi baiknya, ini benar-benar penggunaan paling sederhana yang ternyata paling cepat. Jika Anda membandingkan potongan kode saya (satu baris) dengan jawaban John Kugelman, yang berisi tumpukan dan tumpukan penyesuaian dan optimisasi, yang masih belum cukup menghilangkan perbedaan kinerja, cukup jelas bahwa bagaimanapun
vector
juga dirancang dengan cerdik. Anda tidak harus melompat melewati lingkaran untuk mendapatkan kecepatan yang sama dengan array. Sebaliknya, Anda harus menggunakan solusi sesederhana mungkin.sumber
new[]
melakukan konstruksi standar yang sama yangvector.resize()
melakukannya, namun itu jauh lebih cepat.new[]
+ loop dalam harus sama kecepatannya denganvector.resize()
+ loop dalam, tapi tidak, ini hampir dua kali lebih cepat.malloc
yang tidak menginisialisasi atau membangun sesuatu, sehingga adalah efektif algoritma single-pass seperti sayavector
sampel. Dan untuknew[]
jawabannya jelas bahwa keduanya memerlukan dua lintasan, tetapi dalamnew[]
kasus ini, kompiler dapat mengoptimalkan overhead tambahan itu, yang tidak dilakukan dalamvector
kasing. Tapi saya tidak mengerti mengapa menarik apa yang terjadi dalam kasus suboptimal. Jika Anda peduli dengan kinerja, Anda tidak menulis kode seperti itu.vector::resize()
untuk memberi saya sepotong memori kontingen tanpa membuang waktu memanggil konstruktor yang tidak berguna.malloc
yang tidak melakukan inisialisasi, tetapi itu tidak akan berfungsi di C ++ dengan tipe non-POD. Jadi dalam kasus umum, array C ++ akan sama buruknya. Mungkin pertanyaannya adalah, jika Anda akan sering melakukan blitting ini, bukankah Anda akan menggunakan kembali array / vektor yang sama? Dan jika Anda melakukannya, maka Anda hanya membayar biaya "konstruktor tidak berguna" sekali, di awal. Bagaimanapun juga, blitting sebenarnya sama cepatnya.Itu bukan perbandingan yang adil ketika saya pertama kali melihat kode Anda; Saya pasti berpikir Anda tidak membandingkan apel dengan apel. Jadi saya pikir, mari kita minta konstruktor dan destruktor dipanggil pada semua tes; dan kemudian membandingkan.
Pikiranku, bahwa dengan pengaturan ini, mereka harus persis sama. Ternyata, saya salah.
Jadi mengapa kerugian kinerja 30% ini bahkan terjadi? STL memiliki semua yang ada di header, sehingga seharusnya mungkin bagi kompiler untuk memahami semua yang diperlukan.
Pikiranku adalah bagaimana loop menginisialisasi semua nilai ke konstruktor default. Jadi saya melakukan tes:
Hasilnya seperti yang saya duga:
Ini jelas merupakan sumber perlambatan, fakta bahwa vektor menggunakan copy constructor untuk menginisialisasi elemen dari objek yang dibangun secara default.
Ini berarti, bahwa urutan operasi pseudo berikut terjadi selama konstruksi vektor:
Yang, karena konstruktor salinan implisit yang dibuat oleh kompiler, diperluas ke yang berikut:
Jadi default
Pixel
tetap un-dijalankan, sedangkan sisanya yang dijalankan dengan defaultPixel
's un-diinisialisasi nilai.Dibandingkan dengan situasi alternatif dengan
New[]
/Delete[]
:Mereka semua dibiarkan dengan nilai yang tidak diinisialisasi, dan tanpa iterasi ganda di atas urutan.
Berbekal informasi ini, bagaimana kita mengujinya? Mari kita coba menulis konstruktor salinan implisit secara berlebihan.
Dan hasilnya?
Jadi secara ringkas, jika Anda membuat ratusan vektor sangat sering: pikirkan kembali algoritma Anda .
Bagaimanapun, implementasi STL tidak lebih lambat untuk beberapa alasan yang tidak diketahui, ia hanya melakukan persis apa yang Anda minta; berharap kamu tahu lebih baik.
sumber
Coba nonaktifkan iterator yang dicentang dan bangun dalam mode rilis. Anda seharusnya tidak melihat banyak perbedaan kinerja.
sumber
#define _SECURE_SCL 0
. Itu membuatUseVector
sekitar 4 detik (mirip dengan digcc
bawah) tetapi masih dua kali lebih lambat.-O3
._HAS_ITERATOR_DEBUGGING
dinonaktifkan dalam rilis rilis: msdn.microsoft.com/en-us/library/aa985939(VS.80).aspxSTL (dan lain-lain) GNU, yang diberikan
vector<T>(n)
, default membangun objek prototypalT()
- kompiler akan mengoptimalkan konstruktor kosong - tetapi kemudian salinan sampah apa pun yang ada di alamat memori sekarang dicadangkan untuk objek diambil oleh STL__uninitialized_fill_n_aux
, yang loop mengisi salinan objek itu sebagai nilai default dalam vektor. Jadi, "my" STL tidak membangun perulangan, tetapi membangun kemudian perulangan / penyalinan. Ini kontra intuitif, tetapi saya harus ingat ketika saya mengomentari pertanyaan stackoverflow baru-baru ini tentang hal ini: konstruk / salin bisa lebih efisien untuk referensi benda terhitung dll.Begitu:
atau
adalah - pada banyak implementasi STL - sesuatu seperti:
Masalahnya adalah bahwa generasi pengoptimal kompiler saat ini tampaknya tidak bekerja dari wawasan bahwa temp adalah sampah yang tidak diinisialisasi, dan gagal untuk mengoptimalkan keluar loop dan permintaan copy constructor default. Anda dapat berargumen dengan meyakinkan bahwa kompiler sama sekali tidak boleh mengoptimalkan ini, karena seorang programmer yang menulis di atas memiliki harapan yang masuk akal bahwa semua objek akan identik setelah loop, bahkan jika sampah (peringatan biasa tentang 'identik' / operator == vs memcmp / operator = dll berlaku). Kompiler tidak dapat diharapkan memiliki wawasan tambahan ke dalam konteks yang lebih besar dari std :: vector <> atau penggunaan data yang lebih baru yang akan menyarankan pengoptimalan ini aman.
Ini dapat dikontraskan dengan implementasi langsung yang lebih jelas:
Yang mana kita dapat mengharapkan kompiler untuk mengoptimalkan.
Untuk menjadi sedikit lebih eksplisit tentang justifikasi untuk aspek perilaku vektor ini, pertimbangkan:
Jelas itu perbedaan besar jika kita membuat 10.000 objek independen versus 10.000 referensi data yang sama. Ada argumen yang masuk akal bahwa keuntungan melindungi pengguna kasual C ++ dari melakukan sesuatu yang begitu mahal secara tidak sengaja melebihi biaya konstruksi penyalin yang sulit dioptimalkan.
JAWABAN ASLI (untuk referensi / memahami komentar): Tidak ada peluang. vektor secepat array, setidaknya jika Anda memesan ruang secara masuk akal. ...
sumber
Jawaban Martin York menggangguku karena sepertinya upaya untuk menyapu masalah inisialisasi di bawah karpet. Tapi dia benar untuk mengidentifikasi konstruksi default yang berlebihan sebagai sumber masalah kinerja.
[EDIT: Jawaban Martin tidak lagi menyarankan untuk mengubah konstruktor default.]
Untuk masalah langsung yang ada, Anda tentu bisa memanggil versi 2-parameter
vector<Pixel>
ctor sebagai gantinya:Itu berfungsi jika Anda ingin menginisialisasi dengan nilai konstan, yang merupakan kasus umum. Tetapi masalah yang lebih umum adalah: Bagaimana Anda dapat menginisialisasi secara efisien dengan sesuatu yang lebih rumit daripada nilai konstan?
Untuk ini, Anda dapat menggunakan a
back_insert_iterator
, yang merupakan adaptor iterator. Berikut ini adalah contoh dengan vektorint
s, meskipun ide umum berfungsi dengan baik untukPixel
s:Atau Anda bisa menggunakan
copy()
atautransform()
bukannyagenerate_n()
.The downside adalah bahwa logika untuk membangun nilai awal perlu dipindahkan ke kelas yang terpisah, yang kurang nyaman daripada memilikinya di tempat (meskipun lambdas di C ++ 1x membuat ini jauh lebih baik). Saya juga berharap ini tidak akan secepat versi
malloc()
non-STL yang berbasis, tetapi saya berharap ini akan menjadi dekat, karena hanya melakukan satu konstruksi untuk setiap elemen.sumber
Yang vektor juga memanggil konstruktor Pixel.
Masing-masing menyebabkan hampir satu juta ctor berjalan sesuai waktu Anda.
sunting: lalu ada bagian luar 1 ... 1000 loop, jadi buat satu miliar ctor memanggil!
sunting 2: akan menarik untuk melihat pembongkaran untuk kasus UseArray. Pengoptimal dapat mengoptimalkan semuanya, karena tidak memiliki efek selain membakar CPU.
sumber
Inilah cara kerja
push_back
metode dalam vektor:Setelah memanggil
push_back
item X:Ulang. Jika Anda tidak
reserving
ruang pasti akan lebih lambat. Lebih dari itu, jika itu mahal untuk menyalin item maka 'push_back' seperti itu akan memakanmu hidup-hidup.Mengenai hal
vector
versus array, saya harus setuju dengan orang lain. Jalankan dalam rilis, nyalakan optimisasi, dan pasang beberapa flag lagi sehingga orang-orang yang ramah di Microsoft tidak # @% $ ^ untuk Anda.Satu hal lagi, jika Anda tidak perlu mengubah ukuran, gunakan Boost.Array.
sumber
reserve
seperti yang seharusnya.push_back
telah diamortisasi waktu konstan. Sepertinya Anda menggambarkan proses O (N). (Langkah 1 dan 3 tampaknya benar-benar tidak pada tempatnya.) Apa yang membuatpush_back
lambat untuk OP adalah pemeriksaan jangkauan untuk melihat apakah realokasi perlu terjadi, memperbarui pointer, memeriksa terhadap NULL dalam penempatannew
, dan hal-hal kecil lainnya yang biasanya tenggelam oleh pekerjaan aktual program.reserve
karena masih harus membuat cek (apakah perlu realloc) pada setiappush_back
.vector
kinerja mengubah ukuran itu, itu hanya "ajaib." Di sini, izinkan saya mengklarifikasi sedikit lagi.Beberapa data profiler (piksel sejajar dengan 32 bit):
Blah
Dalam
allocator
:vector
:Himpunan
Sebagian besar overhead ada di copy constructor. Sebagai contoh,
Ini memiliki kinerja yang sama dengan sebuah array.
sumber
pixels.size()
akan rusak.Laptop saya adalah Lenova G770 (RAM 4 GB).
OS adalah Windows 7 64-bit (yang dengan laptop)
Kompiler adalah MinGW 4.6.1.
IDE-nya adalah Code :: Blocks .
Saya menguji kode sumber posting pertama.
Hasil
Pengoptimalan O2
UseArray selesai dalam 2,841 detik
UseVector selesai dalam 2,548 detik
UseVectorPushBack selesai dalam 11,95 detik
Semuanya selesai dalam 17,322 detik
jeda sistem
Pengoptimalan O3
UseArray selesai dalam 1,452 detik
UseVector selesai dalam 2,514 detik
UseVectorPushBack selesai dalam 12.967 detik
Semuanya selesai dalam 16.937 detik
Sepertinya kinerja vektor lebih buruk di bawah optimasi O3.
Jika Anda mengubah loop ke
Kecepatan array dan vektor di bawah O2 dan O3 hampir sama.
sumber
Tolok ukur yang lebih baik (saya pikir ...), kompiler karena optimasi dapat mengubah kode, karena hasil dari vektor / array yang dialokasikan tidak digunakan di mana pun. Hasil:
Penyusun:
CPU:
Dan kodenya:
sumber
Saya melakukan beberapa tes ekstensif yang saya inginkan untuk sementara waktu sekarang. Mungkin juga bagikan ini.
Ini adalah mesin dual boot saya i7-3770, Ram 16GB, x86_64, pada Windows 8.1 dan Ubuntu 16.04. Informasi dan kesimpulan lebih lanjut, komentar di bawah. Diuji baik MSVS 2017 dan g ++ (baik pada Windows dan Linux).
Program Tes
Hasil
Catatan
std::sort()
terlalu (Anda bisa melihatnya berkomentar) tetapi dihapus kemudian karena tidak ada perbedaan relatif yang signifikan.Kesimpulan dan Ucapan Saya
std::array
variasi waktu antara berjalan berturut-turut, sementara yang lain terutama std :: data structs sangat bervariasi dibandingkanstd::array
dan c-style array lebih cepat pada Windows tanpa optimasiPutusan
Tentu saja ini adalah kode untuk bangunan yang dioptimalkan. Dan karena pertanyaannya adalah tentang
std::vector
ya itu banyak! lebih lambat dari array biasa (dioptimalkan / tidak dioptimalkan). Tetapi ketika Anda melakukan benchmark, Anda tentu ingin menghasilkan kode yang dioptimalkan.Bintang pertunjukan bagi saya telah
std::array
.sumber
Dengan opsi yang tepat, vektor dan array dapat menghasilkan asm identik . Dalam kasus ini, tentu saja mereka memiliki kecepatan yang sama, karena Anda juga mendapatkan file yang dapat dieksekusi yang sama.
sumber
By the way memperlambat Anda melihat di kelas menggunakan vektor juga terjadi dengan tipe standar seperti int. Inilah kode multithreaded:
Perilaku dari kode menunjukkan instantiation vektor adalah bagian terpanjang dari kode. Setelah Anda melewati leher botol itu. Sisa kode berjalan sangat cepat. Ini benar, tidak peduli berapa banyak utas yang Anda jalankan.
By the way mengabaikan jumlah benar-benar gila termasuk. Saya telah menggunakan kode ini untuk menguji berbagai hal untuk suatu proyek sehingga jumlah termasuk terus bertambah.
sumber
Saya hanya ingin menyebutkan bahwa vektor (dan smart_ptr) hanyalah lapisan tipis yang ditambahkan di atas array mentah (dan pointer mentah). Dan sebenarnya waktu akses vektor dalam memori terus menerus lebih cepat daripada array. Kode berikut menunjukkan hasil inisialisasi dan akses vektor dan array.
Outputnya adalah:
Jadi kecepatannya akan hampir sama jika Anda menggunakannya dengan benar. (seperti yang disebutkan orang lain menggunakan cadangan () atau mengubah ukuran ()).
sumber
Nah, karena vector :: resize () melakukan lebih banyak pemrosesan daripada alokasi memori biasa (oleh malloc).
Cobalah untuk meletakkan breakpoint di copy constructor Anda (tentukan sehingga Anda dapat breakpoint!) Dan sekarang ada tambahan waktu pemrosesan.
sumber
Saya harus mengatakan bahwa saya bukan ahli dalam C ++. Tetapi untuk menambahkan beberapa hasil percobaan:
kompilasi: gcc-6.2.0 / bin / g ++ -O3 -std = c ++ 14 vector.cpp
mesin:
OS:
Keluaran:
Di sini satu-satunya hal yang saya rasa aneh adalah kinerja "UseFillConstructor" dibandingkan dengan "UseConstructor".
Kode:
Jadi "nilai" tambahan yang disediakan memperlambat kinerja cukup banyak, yang saya pikir disebabkan oleh beberapa panggilan untuk menyalin konstruktor. Tapi...
Menyusun:
Keluaran:
Jadi dalam hal ini, optimasi gcc sangat penting tetapi tidak banyak membantu Anda ketika nilai diberikan sebagai default. Ini, sebenarnya bertentangan dengan biaya kuliah saya. Semoga ini membantu programmer baru ketika memilih format inisialisasi vektor mana.
sumber
Tampaknya bergantung pada flag-flag compiler. Berikut ini adalah kode benchmark:
Bendera pengoptimalan yang berbeda memberikan jawaban berbeda:
Hasil pasti Anda akan bervariasi tetapi ini cukup khas pada mesin saya.
sumber
Dalam pengalaman saya, kadang-kadang, hanya kadang-kadang,
vector<int>
bisa berkali-kali lebih lambat daripadaint[]
. Satu hal yang perlu diingat adalah bahwa vektor vektor sangat berbedaint[][]
. Sebagai elemen mungkin tidak berdekatan dalam memori. Ini berarti Anda dapat mengubah ukuran vektor yang berbeda di dalam yang utama, tetapi CPU mungkin tidak dapat men-cache elemen serta dalam kasusint[][]
.sumber