vector性能調優之resize與reserve


 

vector的resize與reserve

reserve()函數為當前vector預留至少共容納size個元素的空間.(譯注:實際空間可能大於size)

resize() 函數( void resize( size_type size, TYPE val ) )改變當前vector的大小為size,且對新創建的元素賦值val

在這里插入圖片描述
(翻譯:

調整容器大小以包含count元素。

如果當前大小大於count,則容器將被縮減為其第一個count元素,就像重復調用pop_back()一樣。

如果當前大小小於count,則附加元素並用值的副本初始化。)

resize和reserve函數本質都涉及了vector的內存存儲空間,因為vector在內存中是連續存放的,所以當resize的空間大於現有的存儲空間(capacity() 函數 返回當前vector在重新進行內存分配以前所能容納的元素數量.)時,會重新選擇更大的空間,並將所有元素復制過去。resize在初始化內存容量時有對值的初始化,所以此時push_back會產生size+1,內存容量不夠,重新尋找更大的內存空間並復制所有元素,所以這個過程是很費事的。

void testResize(){
    vector<int> vector1;
    vector1.resize(10);
    vector1.push_back(1);
    vector1.push_back(2);
    vector1.push_back(3);
    cout<<"vector1的長度:"<<vector1.size()<<endl;//vector1的長度:13
    for_each(vector1.begin(),vector1.end(),[](int x){cout<<x<<" ";});//0 0 0 0 0 0 0 0 0 0 1 2 3
    cout<<endl<<"當前vector在重新進行內存分配以前所能容納的元素數量:"<<vector1.capacity()<<endl;//20
}
void testReserve(){
    vector<int> vector1;
    vector1.reserve(10);
    vector1.push_back(1);//vector1的長度:3
    vector1.push_back(2);//1 2 3
    vector1.push_back(3);
    cout<<"vector1的長度:"<<vector1.size()<<endl;//vector1的長度:3
    for_each(vector1.begin(),vector1.end(),[](int x){cout<<x<<" ";});// 1 2 3
    cout<<endl<<"當前vector在重新進行內存分配以前所能容納的元素數量:"<<vector1.capacity()<<endl;//10
}

插入測試

接下來探討插入的效率的實例,分別嘗試在插入大數據3.8GB和小數據380MB時,各種情況的實現。

(1)push_back直接插入

結論:費事,在插入的過程中,不斷尋找“庇護所”,不斷“遷移大本營”,舟車勞頓效率低下

void testPushBack_bigsize(){
    vector<int> vector1;
    clock_t start = clock();
    for (int i = 0; i < 1000000000; ++i) {//3814MB
        vector1.push_back(i);
    }
    cout <<"共耗時:"<< (clock() - start)/ CLOCKS_PER_SEC <<"s"<<endl;//共耗時:42s
    cout <<"size:"<<vector1.size() << " capacity:" << vector1.capacity() << endl;//size:1000000000 capacity:1073741824
    clock_t start2 = clock();
    vector1.push_back(1);
    cout <<"共耗時:"<< (clock() - start2)/ CLOCKS_PER_SEC <<"s"<<endl;//共耗時:0s
    cout <<"size:"<<vector1.size() << " capacity:" << vector1.capacity() << endl;//size:1000000001 capacity:1073741824
}

(2)先reserve在push_back

結論:先分配空間再進行后續處理,能夠有效的減少插入時間的損耗,耗時占原插入方式的1/3到1/2之間。

void testPushBack_byReserve_bigsize(){
    vector<int> vector1;
    vector1.reserve(1000000000);//3814MB
    clock_t start = clock();
    for (int i = 0; i < 1000000000; ++i) {
        vector1.push_back(i);
    }
    cout <<"共耗時:"<< (clock() - start)/ CLOCKS_PER_SEC <<"s"<<endl;//共耗時:17s
    cout <<"size:"<<vector1.size() << " capacity:" << vector1.capacity() << endl;//size:1000000000 capacity:1000000000
    clock_t start2 = clock();
    vector1.push_back(1);
    cout <<"共耗時:"<< (clock() - start2)/ CLOCKS_PER_SEC <<"s"<<endl;//共耗時:76s
    cout <<"size:"<<vector1.size() << " capacity:" << vector1.capacity() << endl;//size:1000000001 capacity:2000000000
}
void testPushBack_byReserve_smallsize(){
    vector<int> vector1;
    vector1.reserve(100000000);//381MB
    clock_t start = clock();
    for (int i = 0; i < 100000000; ++i) {
        vector1.push_back(i);
    }
    cout <<"共耗時:"<< (clock() - start)/ CLOCKS_PER_SEC <<"s"<<endl;//共耗時:1s
    cout <<"size:"<<vector1.size() << " capacity:" << vector1.capacity() << endl;//size:100000000 capacity:100000000
    clock_t start2 = clock();
    vector1.push_back(1);
    cout <<"共耗時:"<< (clock() - start2)/ CLOCKS_PER_SEC <<"s"<<endl;//共耗時:2s
    cout <<"size:"<<vector1.size() << " capacity:" << vector1.capacity() << endl;//size:100000001 capacity:200000000
}

(2)先resize在利用坐標進行賦值(相當於插入)

結論:在分配空間時直接對空間進行初始化,賦予初值,極大提升了存儲的速率。但是在resize后進行push_back是不明智的選擇。

void testinsert_byResize_bigsize(){
    vector<int> vector1;
    vector1.resize(1000000000);
    clock_t start = clock();
    for (int i = 0; i < 1000000000; ++i) {
        vector1[i]=i;
    }
    cout <<"共耗時:"<< (clock() - start)/ CLOCKS_PER_SEC <<"s"<<endl;//共耗時:3s
    cout <<"size:"<<vector1.size() << " capacity:" << vector1.capacity() << endl;//size:1000000000 capacity:1000000000
    clock_t start2 = clock();
    vector1.push_back(1);
    cout <<"共耗時:"<< (clock() - start2)/ CLOCKS_PER_SEC <<"s"<<endl;//共耗時:66s
    cout <<"size:"<<vector1.size() << " capacity:" << vector1.capacity() << endl;//size:1000000001 capacity:2000000000
}
void testinsert_byResize_smallsize(){
    vector<int> vector1;
    vector1.resize(100000000);
    clock_t start = clock();
    for (int i = 0; i < 100000000; ++i) {
        vector1[i]=i;
    }
    cout <<"共耗時:"<< (clock() - start)/ CLOCKS_PER_SEC <<"s"<<endl;//共耗時:0s
    cout <<"size:"<<vector1.size() << " capacity:" << vector1.capacity() << endl;//size:size:10000000 capacity:10000000
    clock_t start2 = clock();
    vector1.push_back(1);
    cout <<"共耗時:"<< (clock() - start2)/ CLOCKS_PER_SEC <<"s"<<endl;//共耗時:2s
    cout <<"size:"<<vector1.size() << " capacity:" << vector1.capacity() << endl;//size:10000001 capacity:20000000
}

vector優化結論

防止reallocate內存,而導致的數據拷貝產生的額外耗時

vector在push_back的時候,如果空間不足,會自動增補一些空間,如果沒有預留的空間可用
就直接申請另一塊可用的連續的空間,把數據拷貝過去,然后刪除舊空間,使用新空間
結果造成效率低下 。

可以通過以下兩種組合來防止reallocate.

  1. vector::resize() 使用array index,效率最高,但是需要提前知道size大小

  2. vector::reserve()使用 push_back(),效率一般,較原生有一定提升。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM