 |
Club Builder Foro de C++Builder en español
|
| Ver tema anterior :: Ver tema siguiente |
| Autor |
Mensaje |
Cerúleo Master


Registrado: 04 Ago 2003Mensajes: 332Ubicación: Santander, España
|
Publicado: Lun 09 Ene, 2006 7:34 pm Asunto: Optimización de acceso al disco duro |
|
|
Hola a todos y feliz año.
Revisando algo un antiguo código, he podido comprobar cómo al enviar datos a un fichero de texto (en el disco duro), la ejecución de esa función del programa aumenta mucho la duración. En el ejemplo probado, al escribir unos 240.000 números en varios ficheros de texto la función pasa de tardar 16 s a tardar 1 m y 25 s (antes no los escribía). Inicié la optimización reduciendo el número de veces que abro y cierro cada fichero, dejándolos abiertos en el "exterior" de la función principal y pasándoselos a ésta como parámetro. Luego intenté otra cosa que funcionó muy bien. En vez de escribir 10 números por línea, programé una función que los concatenaba como una cadena de texto, que escribía en el archivo, con lo cual se accedía al disco una sóla vez, en lugar de diez por línea. Con esta mejora, el tiempo de ejecución se reduce a 20 s. Increíble ¿no?
Existe alguna otra línea para seguir optimizando el código, p.e. al leer los datos de los ficheros. Supongo que lo que se nos ocurre a todos es el proceso inverso: leer líneas completas y luego extraer uno a uno los datos.
Espero vuestras sugerencias, opiniones y comentarios.
Un saludo. _________________ Nunca digas "Es imposible" sin intentarlo antes. |
|
| Volver arriba |
|
 |
laremi400 Master

Registrado: 12 May 2004Mensajes: 179
|
Publicado: Mie 11 Ene, 2006 9:26 am Asunto: |
|
|
Hola Cerúleo.
Mira, te paso unos pedazos de código, para que veas como lo hago yo. Utilizo buffers. Un buffer es como esa cadena que concatenas tú, pero un poco mejor y más rápido. Este código que te paso es de un programa en el que se genera un fichero de un inventario para exportar a un cliente. Suele grabar del orden de entre 35.000 y 150.000 registros al día. Y lo hace en muy poquito tiempo. Este fichero se genera y se envía en tiempo real y en grabar esos 150.000 regs. nunca tarda más de un minuto.
Así es como se hace "de toda la vida" cuando se trabaja con ficheros ASCII.
La parte importante de este código es como se gestiona el buffer. "Consulta-FieldValues" y todo eso son datos que saco de una tabla de SQL. A tí me imagino que todo eso te sobra. Pero del resto creo que te puedes hacer una idea de que va.
Si tienes dudas, ya sabes, a tu disposición.
| Código: |
//---------------------------------------------------------------------------
//Envia el fichero del inventario
//Genera un fichero ASCII con toda la informacion disponible
//Se devuelve 1 si no se ha grabado todo o que debia y 0 si es OK
//---------------------------------------------------------------------------
int __fastcall TImportar::EnviaInventario(void)
{
int filas,a,largo,handle,devuelve;
unsigned int longitud;
unsigned long grabados;
AnsiString Fichero,l;
char *buffer;
char cadena[32];
devuelve = 0;
//Se lee todo lo que haya en el inventario
//ejecutar es una funcion que m he hecho yo para evitar teclear cada vez lo mismo.
//Aqui lo que se que hace es sacar un conjunto de registros de la BD
Ejecutar(Datos->Consulta,"Select * from UbiUbicaciones");
if(Datos->Consulta->RecordCount > 0) //si hay datos
{
//Se calcula el tamaño del buffer 20 es el tamaño de la cabecera y 72 bytes por registro
//Se le añaden comas como separador de campos y el punto decimal a la cantidad
longitud = 23 + (Datos->Consulta->RecordCount * 99);
//tenemos un registro con longitud variable. De esta manera se alocata con
//longitud fija pero se pasan datos variables
buffer = new char[longitud+1];// se alocata (reserva, lo siento, soy de la vieja escuela) memoria
longitud = 0;
//Se va llenando la memoria con los datos del inventario
//primero la cabecera
buffer += PasarABuffer(buffer,"H,",2);
buffer += PasarABuffer(buffer,AnsiString().sprintf("%05d",Datos->Consulta->RecordCount)+",",6);
buffer += PasarABuffer(buffer,AnsiString(Fecha->Text.SubString(7,4) + Fecha->Text.SubString(4,2) + Fecha->Text.SubString(1,2))+",",9);
buffer += PasarABuffer(buffer,AnsiString(Hora->Text.SubString(1,2) + Hora->Text.SubString(4,2)),4);
*buffer = 0x0d; buffer++;
*buffer = 0x0a; buffer++;
longitud += 23;
// Y ahora los registros al buffer
filas = 0;
Datos->Consulta->First();
while(filas < Datos->Consulta->RecordCount)
{
buffer += PasarABuffer(buffer,"L,",2);
//*buffer = ' '; buffer++; //Filler
*buffer = ','; buffer++;
buffer += PasarABuffer(buffer,AnsiString(Fecha->Text.SubString(7,4) + Fecha->Text.SubString(4,2) + Fecha->Text.SubString(1,2))+",",9);
buffer += PasarABuffer(buffer,AnsiString(Hora->Text.SubString(1,2) + Hora->Text.SubString(4,2))+",",5);
buffer += PasarABuffer(buffer,AnsiString().sprintf("%06d",filas+1)+",",7);
l = Datos->Consulta->FieldValues["Ubi"];
buffer += PasarABuffer(buffer,AnsiString().sprintf("%18s",l)+",",19);
l = Datos->Consulta->FieldValues["ProductCode"];
buffer += PasarABuffer(buffer,AnsiString().sprintf("%8s",l)+",",9);
l = Datos->Consulta->FieldValues["Quantity"];
l = FloatToStrF(l.ToDouble(),ffFixed,15,3);
l = AnsiString().sprintf("%s",l);
strcpy(cadena,l.c_str());
//se busca la longitud de quantity
largo = 0;
for(a=0;a < 31;a++)
{
if(cadena[a] != 0x00) largo++;
else a = 32;
}
l = AnsiString(cadena).SubString(1,largo-4)+AnsiString(".")+AnsiString(cadena).SubString(largo-2,3);
largo--; //la longitud de la cadena sin el punto decimal
l = AnsiString("00000000000000").SubString(1,14-largo) + l;
buffer += PasarABuffer(buffer,l+",",16);
l = Datos->Consulta->FieldValues["UnitOfM"];
buffer += PasarABuffer(buffer,AnsiString().sprintf("%2s",l)+",",3);
l = Datos->Consulta->FieldValues["BDD"];
buffer += PasarABuffer(buffer,AnsiString().sprintf("%8s",l)+",",9);
l = Datos->Consulta->FieldValues["UbiL"];
buffer += PasarABuffer(buffer,AnsiString().sprintf("%10s",l)+",",11);
//OJO a la longitud. Hasta aqui es fija
longitud += 91;
l = Datos->Consulta->FieldValues["UbiEs"];
l = l.Trim();
buffer += PasarABuffer(buffer,l,l.Length());
longitud += l.Length();//OJO con esto!
*buffer = 0x0d; buffer++;
*buffer = 0x0a; buffer++;
longitud += 2; //Al loro!!!
filas++;
Datos->Consulta->Next();
}
buffer -= longitud;
//Se define el nombre del fichero
Fichero = N->Directory + "\\N" + Fecha->Text.SubString(7,4) + Fecha->Text.SubString(4,2) + Fecha->Text.SubString(1,2) + ".TXT";
handle = FileCreate(Fichero); //se abre solo para escribir
FileWrite(handle, buffer, longitud); //se escribe todo
FileClose(handle); //y se cierra
//Y ahora se hace una segunda escritura para backup
Fichero = NB->Directory + "\\Inventarios\\NB" + Fecha->Text.SubString(7,4) + Fecha->Text.SubString(4,2) + Fecha->Text.SubString(1,2) + ".TXT";
handle = FileCreate(Fichero); //se abre solo para escribir
grabados = FileWrite(handle, buffer, longitud); //se escribe todo
if(grabados != longitud) devuelve = 1;
FileClose(handle); //y se cierra
delete [] buffer; //se libera. importante, no hay que olivdarlo
}
return(devuelve);
}
//---------------------------------------------------------------------------
// Pasa al buffer el contenido de la variable. devuelve la longitud para
// que se pueda desplazar el buffer cosa que aqui no se hace
//(no se porque, no me acuerdo por que lo hice)
//---------------------------------------------------------------------------
int PasarABuffer(char *Buffer,AnsiString Variable,int Longitud)
{
int a;
char cadena[256];
strcpy(cadena,Variable.c_str());
for(a=0;a < Longitud;a++) {*Buffer = cadena[a]; Buffer++;}
return(Longitud);
} |
|
|
| Volver arriba |
|
 |
|
|
No puedes publicar temas nuevos en este foro No puedes responder a temas en este foro No puedes editar tus mensajes en este foro No puedes borrar tus mensajes en este foro No puedes votar en las encuestas de este foro
|
© 2002–2026 Club Builder · Funciona con phpBB.
|