ОГРОМНЫЙ файл .cpp лучше, чем чтение из текстового файла? - PullRequest
3 голосов
/ 19 октября 2011

Является ли законной оптимизация простым созданием действительно ОГРОМНОГО исходного файла, который инициализирует вектор с сотнями тысяч значений вручную? вместо того, чтобы разбирать текстовый файл с теми же значениями в вектор?

Извините, что, возможно, лучше сформулировать. Функция, которая анализирует текстовый файл, очень медленная из-за очень медленного чтения потока C ++ (занимает около 6 минут против 6 секунд в версии C #.

Было бы допустимым сделать файл инициализации массива массива? Это не кажется элегантным, но если это быстрее, то я полагаю, что это лучше?

это код чтения файла:

    //parses the text path vector into the engine
    void Level::PopulatePathVectors(string pathTable)
    {
        // Read the file line by line.
        ifstream myFile(pathTable);

            for (unsigned int i = 0; i < nodes.size(); i++)
            {
                pathLookupVectors.push_back(vector<vector<int>>());

                for (unsigned int j = 0; j < nodes.size(); j++)
                {
                    string line;

                    if (getline(myFile, line)) //enter if a line is read successfully
                    {
                        stringstream ss(line);
                        istream_iterator<int> begin(ss), end;
                        pathLookupVectors[i].push_back(vector<int>(begin, end));
                    }
                }
            }
        myFile.close();
    }

образец строки из текстового файла (в котором около полумиллиона строк аналогичного формата, но различной длины.

0 5 3 12 65 87 n

Ответы [ 7 ]

4 голосов
/ 19 октября 2011

Сначала убедитесь, что вы компилируете с наивысшим доступным уровнем оптимизации, затем добавьте следующие строки, отмеченные ниже, а затем протестируйте снова. Я сомневаюсь, что это решит проблему, но это может помочь. Трудно сказать, пока я не увижу результаты.

//parses the text path vector into the engine
void Level::PopulatePathVectors(string pathTable)
{
    // Read the file line by line.
    ifstream myFile(pathTable);

    pathLookupVectors.reserve(nodes.size()); // HERE
    for (unsigned int i = 0; i < nodes.size(); i++)
    {
        pathLookupVectors.push_back(vector<vector<int> >(nodes.size()));
        pathLookupVectors[i].reserve(nodes.size());  // HERE

        for (unsigned int j = 0; j < nodes.size(); j++)
        {
            string line;

            if (getline(myFile, line)) //enter if a line is read successfully
            {
                stringstream ss(line);
                istream_iterator<int> begin(ss), end;
                pathLookupVectors[i].push_back(vector<int>(begin, end));
            }
         }
     }
     myFile.close();
}
3 голосов
/ 19 октября 2011

6 минут против 6 секунд !! должно быть что-то не так с вашим кодом C ++. Оптимизируйте его, используя старые добрые методы, прежде чем вернуться к такой экстремальной «оптимизации», упомянутой в вашем посте.

Также знайте, что чтение из файла позволит вам изменять векторное содержимое без изменения исходного кода. Если вы сделаете это так, как упомянули об этом, вам придется перекодировать, скомпилировать n ссылку заново.

2 голосов
/ 19 октября 2011

В зависимости от изменения данных.Если данные могут / должны быть изменены (после компиляции), тогда единственный вариант - загрузить их из текстового файла.Если нет, то я не вижу никакого вреда для его компиляции.

1 голос
/ 20 октября 2011

Мне удалось получить следующий результат с Boost.Spirit 2.5:

$ time ./test input

real    0m6.759s
user    0m6.670s
sys     0m0.090s

'input' - это файл, содержащий 500 000 строк, содержащих 10 случайных целых чисел от 0 до 65535 каждая.

Вот код:

#include <vector>

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/classic_file_iterator.hpp>

using namespace std;
namespace spirit = boost::spirit;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

typedef vector<int> ragged_matrix_row_type;
typedef vector<ragged_matrix_row_type> ragged_matrix_type;


template <class Iterator>
struct ragged_matrix_grammar : qi::grammar<Iterator, ragged_matrix_type()> {

  ragged_matrix_grammar() : ragged_matrix_grammar::base_type(ragged_matrix_) {

    ragged_matrix_ %= ragged_matrix_row_ % qi::eol;
    ragged_matrix_row_ %= qi::int_ % ascii::space;

  }

  qi::rule<Iterator, ragged_matrix_type()> ragged_matrix_;
  qi::rule<Iterator, ragged_matrix_row_type()> ragged_matrix_row_;

};

int main(int argc, char** argv){

  typedef spirit::classic::file_iterator<> ragged_matrix_file_iterator;

  ragged_matrix_type result;
  ragged_matrix_grammar<ragged_matrix_file_iterator> my_grammar;
  ragged_matrix_file_iterator input_it(argv[1]);

  qi::parse(input_it, input_it.make_end(), my_grammar, result);

  return 0;

}

На этом этапе result содержит неровную матрицу, что можно подтвердить печатью ее содержимого.В моем случае «рваная матрица» не такая рваная - это прямоугольник 500000 x 10, но это не имеет значения, потому что я уверен, что грамматика верна.Я получил еще лучшие результаты, когда прочитал весь файл в память перед синтаксическим анализом (~ 4 с), но код для этого длиннее, и, как правило, нежелательно копировать большие файлы в память целиком.

Примечание: на моей тестовой машине установлен SSD, поэтому я не знаю, получите ли вы те же цифры, что и я (если только на вашей тестовой машине нет и SSD).

HTH!

0 голосов
/ 19 октября 2011

использование огромного массива в файле C ++ - это полностью допустимая опция, в зависимости от случая.

Вы должны учитывать, будут ли данные меняться и как часто.

Если вы поместите его в файл C ++, это означает, что вам придется перекомпилировать вашу программу каждый раз, когда изменяются данные (и каждый раз распространять ее среди ваших клиентов!), Так что это не будет хорошим решением, если у вас есть распространять программу другим людям.

Теперь, если компиляция разрешена для каждого изменения данных, тогда вы можете иметь лучший из двух миров: просто используйте небольшой скрипт (например, в python или perl), который возьмет ваш .txt и сгенерирует файл C ++, так что синтаксический анализ файла должен быть выполнен только один раз для каждого изменения данных. Вы даже можете интегрировать этот шаг в процесс сборки с автоматическим управлением зависимостями.

Удачи!

0 голосов
/ 19 октября 2011

Я бы не считал компиляцию статических данных в ваше приложение плохой практикой. Если существует небольшая мыслимая необходимость изменить ваши данные без перекомпиляции, анализ файла во время компиляции не только повышает производительность во время выполнения (поскольку ваши данные были предварительно проанализированы компилятором и находятся в пригодном для использования формате во время выполнения), но также уменьшает риски (например, файл данных не найден во время выполнения или любые другие ошибки синтаксического анализа).

Убедитесь, что пользователям не нужно будет изменять данные (или иметь средства для перекомпиляции программы), документировать свою мотивацию, и у вас должно быть все в порядке.

Тем не менее, вы можете сделать версию iostream намного быстрее, если это необходимо.

0 голосов
/ 19 октября 2011

Не используйте поток ввода std, он очень медленный.Есть лучшие альтернативы.

Поскольку люди решили понизить мой ответ, потому что им лень пользоваться Google, здесь:

http://accu.org/index.php/journals/1539

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...