Club Builder - Foros de discusión Club Builder
Foro de C++Builder en español
 
 FAQFAQ   BuscarBuscar   MiembrosMiembros   Grupos de UsuariosGrupos de Usuarios   RegistrarseRegistrarse 
 PerfilPerfil   Entra para ver tus mensajes privadosEntra para ver tus mensajes privados   EntrarEntrar 

Optimización de acceso al disco duro

 
Publicar nuevo tema   Responder al tema    Foros de discusión -> Consultas
Ver tema anterior :: Ver tema siguiente  
Autor Mensaje
Mensaje    Asunto: Optimización de acceso al disco duro Responder citando

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
Ver perfil de usuario Enviar mensaje privado Enviar email
Mensaje    Asunto: Responder citando

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
Ver perfil de usuario Enviar mensaje privado
Mostrar mensajes de anteriores:   
Cambiar a:  
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


Hosting WordPress Indedmedia desde 3,99 €
© 2002–2026 Club Builder · Funciona con phpBB.