Ще видя ли увеличение на производителността, използвайки std::map вместо vector‹pair‹string, string› ›?

В момента имам някакъв код, където използвам vector от pair<string,string>. Това се използва за съхраняване на някои данни от XML парсинг и като такъв процесът е доста бавен на места. По отношение на опита да ускоря целия процес, се чудех дали ще има някакво предимство в производителността при преминаването от vector<pair<string,string> > към std::map<string,string>? Бих могъл да го кодирам и да стартирам профайлър, но си помислих, че първо ще видя дали мога да получа отговор, който предполага някакво очевидно увеличение на производителността. Не съм длъжен да правя каквото и да е сортиране, просто добавям елементи към вектора, след което на по-късен етап итерирам съдържанието и извършвам някаква обработка - нямам нужда от сортиране или нещо подобно. Предполагам, че може би няма да получа никаква печалба в производителността, но всъщност никога не съм използвал std::map преди, така че не знам, без да питам или да кодирам всичко.


person mathematician1975    schedule 02.10.2012    source източник
comment
Мисля, че това зависи най-вече от това как ще осъществявате достъп до данните и дали е важно те да останат сортирани.   -  person jpm    schedule 02.10.2012
comment
Известната обработка, която споменавате там, наистина е ключът към вашия въпрос. Без да знаем какъв вид обработка извършвате с тези данни, ние не можем да помогнем.   -  person Collin    schedule 02.10.2012
comment
Свързан въпрос: stackoverflow.com/q/1822114/501250   -  person cdhowie    schedule 02.10.2012
comment
Когато профилирахте съществуващия си код (направихте го, нали?), показа ли, че изграждането или достъпът до този вектор е тясно място? Ако е така, опитахте ли да прецените крайния размер на вектора и да го резервирате предварително?   -  person Useless    schedule 02.10.2012
comment
Ако имате груба представа колко елемента ще завърши векторът, можете значително да ускорите вмъкванията, като извикате reserve(n) на вектора, където n е броят на елементите, които очаквате.   -  person Pete Becker    schedule 02.10.2012
comment
възможен дубликат на C++ STL Map vs Vector speed   -  person Kiril    schedule 02.10.2012
comment
картата е асоциативна, векторът е последователен. Ако не търсите по ключ, картата вероятно ще направи нещата по-бавни. Може би вашата логика за повторение на контейнера е проблемът, може би трябва да препроектирате, за да използвате контейнера по-интелигентно. Профил, след което направете необходимите модификации за приемливо представяне в реалния свят.   -  person Steve Townsend    schedule 02.10.2012
comment
Бих се съмнявал. Ако итерирате само елементи. Търсенето на елемент вероятно ще бъде по-бързо с map. Тъй като няма да е необходимо да сравнявате низове, а хешове.   -  person luk32    schedule 02.10.2012


Отговори (5)


Не. Ако (както казвате) просто итерирате колекцията, ще видите малко (вероятно неизмеримо) намаляване на производителността чрез използване на std::map.

Картите са за достъп до стойност чрез нейния ключ. Ако никога не правите това, map е лош избор за контейнер.

person meagar    schedule 02.10.2012

Ако не модифицирате своя vector<pair<string,string> > - просто го итерирате отново и отново - ще получите влошаване на производителността, като използвате map. Това е така, защото типичният map е организиран с двоично дърво от обекти, всеки от които може да бъде разпределен в различни блокове памет (освен ако не напишете собствен разпределител). Плюс това, всеки възел на map управлява указатели към съседни обекти, така че това също е време и памет. Но търсенето по ключ е O(log) операция. От друга страна, vector съхранява данни в един блок, така че кешът на процесора обикновено се чувства по-добре с него. Търсенето във вектор всъщност е O(N) операция, която не е толкова добра, но приемлива. Търсенето в сортирания вектор може да бъде надстроено до O(log) с помощта на функции на lower_bound и т.н.

Зависи от операциите, които извършвате с тези данни. Ако правите много търсения - вероятно е по-добре да използвате хеширащ контейнер като unordered_map, тъй като търсенето по ключ в тези контейнери е O(1) операция. За итерация, както споменахме, vector е по-бързо.

Вероятно си струва да замените string във вашия pair, но това много зависи от това какво държите там и как имате достъп до контейнера.

person PSIAlt    schedule 02.10.2012

Отговорът зависи от това какво правите с тези структури от данни и какъв е размерът им. Ако имате хиляди елементи във вашия std::vector<std::pair<std::stringm std::string> > и продължавате да търсите елемента first отново и отново, използването на std::map<std::string, std::string> може да подобри производителността (може да обмислите използването на std::unordered_map<std::string, std::string> за този случай на употреба вместо това). Ако вашите вектори са относително малки и не се опитвате да вмъквате елементи в средата твърде често, използването на вектори може да бъде много по-бързо. Ако просто итерирате върху елементите, векторите са много по-бързи от картите: итерациите всъщност не са една от силните им страни. Картите са добри в разглеждането на нещата, ако приемем, че броят на елементите не е наистина малък, защото в противен случай линейното търсене върху вектор е все още по-бързо.

Най-добрият начин да определите къде е изразходвано времето е да профилирате кода: често не е напълно ясно отпред къде е изразходвано времето. Често предполагаемите горещи точки всъщност не са проблемни, а други области показват неочаквани проблеми с производителността. Например, може да предавате на своите обекти моята стойност, а не чрез препратка на някое неясно място.

person Dietmar Kühl    schedule 02.10.2012

Ако вашият модел на използване е такъв, че извършвате много вмъквания, преди да извършите каквото и да е търсене, тогава може да се възползвате от прилагането на „мързелива“ карта, където елементите се сортират при поискване (т.е. когато придобиете итератор, извършите търсене и т.н.).

person Andrew Durward    schedule 02.10.2012

Както C++ казва std::vector сортира елементи в линейна памет, така че първо разпределя блок памет с първоначален капацитет и след това, когато искате да вмъкнете нов елемент във вектор, той ще провери дали има повече място или не и ако не, ще разпредели нов буфер с повече място, копирайте конструирайте всички елементи в нов буфер и след това изтрийте изходния буфер и го настройте на нов.

Когато току-що започнете да вмъквате елементи в vector и имате много елементи, страдате от твърде много преразпределения, копиране на конструкции и извикване на деструктор.

За да разрешите този проблем, ако сега преброите входните елементи (не точно, но обичайната му дължина), можете да reserve малко памет за вектора и да избегнете преразпределението и всичко друго. ако нямате представа за размера, можете да използвате колекция като std::list, която никога не преразпределя своите вътрешни елементи.

person BigBoss    schedule 02.10.2012