function setCookie(cname,cvalue,exdays) {
var d = new Date();
d.setTime(d.getTime() + (exdays*24*60*60*1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname+"="+cvalue+"; "+expires;
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1);
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
function checkCookie() {
var user=getCookie("username");
if (user != "") {
alert("Welcome again " + user);
} else {
user = prompt("Please enter your name:","");
if (user != "" && user != null) {
setCookie("username", user, 30);
}
}
}
У вас есть две проблемы, касающиеся скорости операций записи и чтения.
Во-первых, std::copy не может выполнить оптимизацию блочного копирования при записи в выходной_итератор, потому что у него нет прямого доступа к базовой цели.
Во-вторых, вы записываете целые числа в формате ascii, а не в двоичном, поэтому на каждой итерации записи output_iterator создает ascii представление вашего int, а на чтении ему приходится разбирать текст обратно в целые числа. Я считаю, что это основная проблема производительности.
Необработанное хранилище вашего массива (при условии, что int состоит из 4 байт) должно быть всего 60 МБ, но поскольку каждый символ целого числа в ascii равен 1 байту, любые int с более чем 4 символами будут больше, чем двоичное хранилище, отсюда и ваш файл размером 130 МБ.
Не существует простого способа решить проблему скорости портативно (чтобы файл можно было читать на разных машинах с эндианом или интом) или при использовании std::copy. Самый простой способ - просто сбросить весь массив на диск, а затем прочитать его обратно, используя fstream.write и read, только помните, что это не совсем переносимо.
Для записи:
std::fstream out(config.c_str(), ios::out | ios::binary);
out.write( keys.data(), keys.size() * sizeof(int) );
И для чтения:
std::fstream in(config.c_str(), ios::in | ios::binary);
in.read( keys.data(), keys.size() * sizeof(int) );
----Update----
Если вы действительно озабочены переносимостью, вы можете легко использовать переносимый формат (например, вашу начальную версию ascii) в артефактах дистрибутива, а затем, когда программа запускается впервые, она может преобразовать этот переносимый формат в локально оптимизированную версию для использования во время последующих запусков.
Возможно, что-то вроде этого:
std::array<int, 15000000> keys;
// data.txt are the ascii values and data.bin is the binary version
if(!file_exists("data.bin")) {
std::ifstream in("data.txt");
std::copy(std::istream_iterator<int>(in),
std::istream_iterator<int>(), keys.begin());
in.close();
std::fstream out("data.bin", ios::out | ios::binary);
out.write( keys.data(), keys.size() * sizeof(int) );
} else {
std::fstream in("data.bin", ios::in | ios::binary);
in.read( keys.data(), keys.size() * sizeof(int) );
}
Если у вас есть процесс установки, эта предварительная обработка также может быть выполнена в это время...
если целые числа сохраняются в двоичном формате и вас не интересуют проблемы с порядком байтов, попробуйте прочитать весь файл в память сразу (fread) и приведите указатель к int *
Вы можете предварительно скомпилировать массив в файл .o, который не нужно будет перекомпилировать, если данные не изменятся.
thedata.hpp:
static const int NUM_ENTRIES = 5;
extern int thedata[NUM_ENTRIES];
thedata.cpp:
#include "thedata.hpp"
int thedata[NUM_ENTRIES] = {
10
,200
,3000
,40000
,500000
};
Чтобы скомпилировать это:
# make thedata.o
Тогда ваше основное приложение будет выглядеть примерно так:
#include "thedata.hpp"
using namespace std;
int main() {
for (int i=0; i<NUM_ENTRIES; i++) {
cout << thedata[i] << endl;
}
}
Предполагая, что данные не меняются часто, и что вы можете обрабатывать данные для создания thedata.cpp, то это фактически мгновенная загрузка. Я не знаю, захлебнется ли компилятор таким большим литеральным массивом!
Если числа никогда не меняются, предварительно обработайте файл в исходный код C ++ и скомпилируйте его в приложение.
Если число может измениться, и, следовательно, вы должны сохранить их в отдельном файле, который вы должны загрузить при запуске, не используйте это число по номеру, используя потоки ввода-вывода C ++. Потоки ввода-вывода C ++ - хорошая абстракция, но их слишком много для такой простой задачи, как быстрая загрузка группы чисел. По моему опыту, огромная часть времени выполнения тратится на анализ чисел, а другая - на доступ к файлу char с помощью char.
(Предполагая, что ваш файл состоит из более чем одной длинной строки.) Прочтите файл построчно, используя std :: getline ()
, проанализируйте числа из каждой строки, используя не потоки, а std: : strtol ()
. Это позволяет избежать огромных накладных расходов. Вы можете увеличить скорость потоков, создав свой собственный вариант std :: getline ()
, который считывает ввод вперед (с помощью istream :: read ()
); стандартный std :: getline ()
также считывает входной char по char.
Чтение целых чисел из большого текстового файла является операцией, связанной с вводом-выводом, если вы не делаете что-то совершенно неправильно (например, используете для этого потоки C ++). Загрузка 15M целых чисел из текстового файла занимает менее 2 секунд на AMD64 @ 3GHZ, когда файл уже буферизован (и немного дольше, если нужно было получить с достаточно быстрого диска).Вот быстрая и грязная процедура, чтобы доказать мою точку зрения (поэтому я не проверяю все возможные ошибки в формате целых чисел и не закрываю свои файлы в конце, потому что я все равно exit ()).
$ wc nums.txt
15000000 15000000 156979060 nums.txt
$ head -n 5 nums.txt
730547560
-226810937
607950954
640895092
884005970
$ g++ -O2 read.cc
$ time ./a.out <nums.txt
=>1752547657
real 0m1.781s
user 0m1.651s
sys 0m0.114s
$ cat read.cc
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <vector>
int main()
{
char c;
int num=0;
int pos=1;
int line=1;
std::vector<int> res;
while(c=getchar(),c!=EOF)
{
if (c>='0' && c<='9')
num=num*10+c-'0';
else if (c=='-')
pos=0;
else if (c=='\n')
{
res.push_back(pos?num:-num);
num=0;
pos=1;
line++;
}
else
{
printf("I've got a problem with this file at line %d\n",line);
exit(1);
}
}
// make sure the optimizer does not throw vector away, also a check.
unsigned sum=0;
for (int i=0;i<res.size();i++)
{
sum=sum+(unsigned)res[i];
}
printf("=>%d\n",sum);
}
ОБНОВЛЕНИЕ: и вот мой результат при чтении текстового файла (не двоичного) с использованием кода mmap:
$ g++ -O2 mread.cc
$ time ./a.out nums.txt
=>1752547657
real 0m0.559s
user 0m0.478s
sys 0m0.081s
в pastebin:
1-2 секунды - реалистичная нижняя граница для типичной настольной машины для загрузки этих данных. 2 минуты больше похоже на считывание микроконтроллером 60 МГц с дешевой SD-карты. Итак, либо у вас есть необнаруженное / не упомянутое аппаратное состояние , либо ваша реализация потока C ++ каким-то образом сломана или непригодна для использования. Я предлагаю установить нижнюю границу для этой задачи на вашем компьютере, запустив мой пример кода.
Используйте буфер из 1000 (или даже 15 МБ, вы можете изменять этот размер по своему усмотрению) целых чисел, а не целого числа после целого. Я считаю, что проблема не в использовании буфера.
Если данные в файле двоичные, и вам не нужно беспокоиться о порядке байтов, и вы работаете в системе, которая его поддерживает, используйте системный вызов mmap . См. Эту статью на веб-сайте IBM:
Также см. Это сообщение SO:
Сохраните файл в двоичном формате.
Запишите файл, взяв указатель на начало массива int
и преобразуя его в указатель char
. Затем запишите в файл символы 15000000 * sizeof (int)
.
И когда вы читаете файл, сделайте то же самое в обратном порядке: прочтите файл как последовательность символов, возьмите указатель на начало последовательности и преобразуйте его в int *
.
Конечно, это предполагает, что порядок байтов не является проблемой.
Для фактического чтения и записи файла отображение памяти, вероятно, является наиболее разумным подходом.