Я пишу модуль вывода результатов для высокоскоростной вычислительной программы.
Мой план:
- Моя задача - вставить результаты в базу данных (PostgreSQL) с относительнойбыстрая скорость.
- Я использую [COPY FROM STDIN] libpq, который мне сказали как самый быстрый способ.
- Метод требует преобразования результатов в формат char *.
Хотя результаты выглядят так:
- Ежемесячный денежный поток в течение следующих 106 лет (всего 1272 в два раза).
- Около 14 денежных потоков на каждого участника.
- Около 2800 объектов (2790 для проверенных данных).
И таблица в базе данных выглядит следующим образом:
- Каждая строка таблицы содержит один объект.
- Существуют некоторые префиксы для идентификации различных сущностей.
- CashFlow - двойной массив, следующий за префиксом (тип float8 [] в PGSQL).
Ниже представлен коддля создания таблицы в базе данных:
create table AgentCF(
PlanID int4,
Agent int4,
Senario int4,
RM_Prev float8[], DrvFac_Cur float8[], Prem float8[],
Comm float8[], CommOR float8[], FixExp float8[],
VarExp float8[], CIRCFee float8[], SaftyFund float8[],
Surr float8[], Benefit_1 float8[], Benefit_2 float8[],
Benefit_3 float8[], Benefit_4 float8[], Benefit_5 float8[],
Benefit_6 float8[], Benefit_7 float8[], Benefit_8 float8[],
Benefit_9 float8[], Benefit_10 float8[]
);
Представление cода для функции, которая готовит вставленный CashFlow:
void AsmbCF(char *buffer, int size, int ProdNo, int i, int Pos, int LineEnd)
{
int j, Step = sizeof(nodecf) / sizeof(double), PosST, Temp;
double *LoopRate = &AllHeap[ProdNo].Heap.AgentRes[i].CF.NodeCF[0].Prem;
strcpy_s(buffer, size, "{");
for (j = 0; j < TOTLEN / 10; j++) {
PosST = j * 10 * Step + Pos;
sprintf_s(&buffer[strlen(buffer)], size - strlen(buffer), "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,",
LoopRate[PosST],
LoopRate[PosST + 1 * Step],
LoopRate[PosST + 2 * Step],
LoopRate[PosST + 3 * Step],
LoopRate[PosST + 4 * Step],
LoopRate[PosST + 5 * Step],
LoopRate[PosST + 6 * Step],
LoopRate[PosST + 7 * Step],
LoopRate[PosST + 8 * Step],
LoopRate[PosST + 9 * Step]
);
}
Temp = j * 10;
PosST = Temp * Step + Pos;
sprintf_s(&buffer[strlen(buffer)], size - strlen(buffer), "%f", LoopRate[PosST]);
Temp = Temp + 1;
for (j = Temp; j < TOTLEN; j++) {
PosST = j * Step + Pos;
sprintf_s(&buffer[strlen(buffer)], size - strlen(buffer), ",%f", LoopRate[PosST]);
}
if (LineEnd) {
strcat_s(buffer, size, "}\n");
}
else {
strcat_s(buffer, size, "}\t");
}
}
Ниже приведен код для скоростного тестирования:
void ThreadOutP(LPVOID pM)
{
char *buffer = malloc(BUFFLEN), sql[SQLLEN];
int Status, ProdNo = (int)pM, i, j, ben;
PGconn *conn = NULL;
PGresult *res;
clock_t begin, end;
fprintf_s(fpOutP, "PlanID %d Start inseting...\n", AllHeap[ProdNo].PlanID);
begin = clock();
DBConn(&conn, CONNSTR, fpOutP);
#pragma region General cashflow
//============================== Data Query ==============================
//strcpy_s(&sql[0], SQLLEN, "COPY AgentCF(PlanID,Agent,Senario,Prem,Comm,CommOR,CIRCFee,SaftyFund,FixExp,VarExp,Surr");
//for (ben = 1; ben <= AllHeap[ProdNo].Heap.TotNo.NoBenft; ben++) {
// strcat_s(&sql[0], SQLLEN, ",Benefit_");
// _itoa_s(ben, &sql[strlen(sql)], sizeof(sql) - strlen(sql), 10);
//}
//strcat_s(&sql[0], SQLLEN, ") FROM STDIN;");
//res = PQexec(conn, &sql[0]);
//if (PQresultStatus(res) != PGRES_COPY_IN) {
// fprintf_s(fpOutP, "Not in COPY_IN mode\n");
//}
//PQclear(res);
//============================== Data Apply ==============================
for (i = 0; i < AllHeap[ProdNo].MaxAgntPos + AllHeap[ProdNo].Heap.TotNo.NoSensi; i++) {
sprintf_s(buffer, BUFFLEN, "%d\t%d\t%d\t", AllHeap[ProdNo].PlanID, AllHeap[ProdNo].Heap.AgentRes[i].Agent, AllHeap[ProdNo].Heap.AgentRes[i].Sensi);
//Status = PQputCopyData(conn, buffer, (int)strlen(buffer));
//if (1 != Status) {
// fprintf_s(fpOutP, "PlanID %d inserting error for agent %d\n", AllHeap[ProdNo].PlanID, AllHeap[ProdNo].Heap.AgentRes[i].Agent);
//}
for (j = 0; j < 8 + AllHeap[ProdNo].Heap.TotNo.NoBenft; j++) {
if (j == 7 + AllHeap[ProdNo].Heap.TotNo.NoBenft) {
AsmbCF(buffer, BUFFLEN, ProdNo, i, j, 1);
}
else {
AsmbCF(buffer, BUFFLEN, ProdNo, i, j, 0);
}
//Status = PQputCopyData(conn, buffer, (int)strlen(buffer));
//if (1 != Status) {
// fprintf_s(fpOutP, "PlanID %d inserting error for agent %d\n", AllHeap[ProdNo].PlanID, AllHeap[ProdNo].Heap.AgentRes[i].Agent);
//}
}
}
//Status = PQputCopyEnd(conn, NULL);
#pragma endregion
#pragma region K cashflow
#pragma endregion
PQfinish(conn);
FreeProd(ProdNo);
free(buffer);
end = clock();
fprintf_s(fpOutP, "PlanID %d inserted, total %d rows inserted, %d millisecond cost\n", AllHeap[ProdNo].PlanID, i, end - begin);
AllHeap[ProdNo].Printed = 1;
}
Обратите внимание, что я отключаю код, который включает вставку.
Результаты тестирования:
- Стоимость только сборки строки составляет 45930 миллисекунд.
- Стоимость сборки строки и вставки составляет 54829 миллисекунд.
Таким образом, большая часть затрат заключается в преобразовании double в char.
Поэтому я хотел бы спросить, существует ли более быстрый способ преобразования серии double в строку, потому что по сравнению с затратами на вычислениеУзким местом является вывод результатов.
Кстати, моя платформа - Windows 10, PostgreSQL 11, Visual Studio 2017.
Большое спасибо!