Multi-string vs wektor stringów

0

Czysta ciekawość skłoniła mnie do sprawdzenia pewnej rzeczy. Czy przechowywanie kilku stringów w jednym std::string będzie miało jakieś plusy w porównaniu do wektora stringów?
Przyznam, że spodziewałem się iż co najmniej wyszukiwanie będzie szybsze z powodu 'biegania' po ciągłym bloku pamięci a nie skakaniu po pamięci.

#include <string>
#include <string_view>
#include <vector>
#include <chrono>
#include <algorithm>

using namespace std;

constexpr string base{"veryveryverylonglonglongstring_"};
constexpr string_view to_find{"veryveryverylonglonglongstring_915000"};
constexpr size_t max_size = 1000000u;

void multi_string()
{
  string storage;
  for (auto i = 0u; i < max_size; ++i) {
    storage += string{base + std::to_string(i) + '\0'};
  }
  auto currptr = storage.data();
  auto fin = storage.data() + storage.length();
  auto start = chrono::steady_clock::now();
  while (currptr < fin) {
    string_view current{currptr};
    if (current == to_find) {
      break;
    }
    currptr += current.length() + 1;
  }
  auto elapsed = chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - start);
  cout << "Multistring -> " << elapsed.count() << "\n":
}

void vector_string()
{
  vector<string> storage;
  for (auto i = 0u; i < max_size; ++i) {
    storage.push_back(string{base + to_string(i)});
  }
  auto start = chrono::steady_clock::now();
  auto iter = std::find(storage.begin(), storage.end(), to_find);
  auto elapsed = chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - start);
  cout << "Vector -> " << elapsed.count() << "\n":
}

int main(int argc, char** argv)
{
  multi_string();
  vector_string();
  return 0;
}

Wyniki:
Multistring -> 42
Vector -> 17

VS2017, release x64 + optymalizacja O2

Dlaczego skakanie po wskaźnikach z std::string jest ponad 2x szybsze niż iterowanie po ciągłym bloku? Gdzieś się machnąłem?

0

constexpr string base{"veryveryverylonglonglongstring_"};
To działa? Z tego co mi wiadomo std::string nie może być constexpr

1

to mi wygląda na problem XY. Co chcesz zrobić?
Może unordered_set/map da ci lepsze przyspieszenie?

Przy sklejanym stringu wyszukanie musi czytać wszsytkie kolejne bajty.
jak nie dopasuje się do veryveryverylonglonglongstring_1 to potemto potem sprawdz od e potem od r ...... a potem jeszcze veryvery, itd itp.
Przy wyszukaniu w wektorze, jeśli słowo nie pasuje to odr razu skacze do następnego, a nie próbuje znaleźć podciągu zaczynając od kolejnych liter.

0

poczytaj o string_view w c++17.

0
MarekR22 napisał(a):

to mi wygląda na problem XY. Co chcesz zrobić?
Może unordered_set/map da ci lepsze przyspieszenie?

Chcę się pobawić stringami (jakkolwiek to nie brzmi :D)
Tak sobie luźno rozmyślam jak można ograniczyć alokacje przy stringach. Opcja z unordered_map może być ciekawa.

Przy sklejanym stringu wyszukanie musi czytać wszsytkie kolejne bajty.
jak nie dopasuje się do veryveryverylonglonglongstring_1 to potemto potem sprawdz od e potem od r ...... a potem jeszcze veryvery, itd itp.
Przy wyszukaniu w wektorze, jeśli słowo nie pasuje to odr razu skacze do następnego, a nie próbuje znaleźć podciągu zaczynając od kolejnych liter.

Problemem okazał się konstruktor string_view(const char*), który dla każdego stringa musiał sobie wyliczyć długość. Jak pozapamiętywałem kolejne offsety z których mogłem wyliczyć długość to czas zrównał się z opcją 'wektorową' do ~16ms. I tak jestem zawiedziony :P

1 użytkowników online, w tym zalogowanych: 0, gości: 1