PDA

Ver la Versión Completa : donde es mejor utilizar hilo


juank1971
07-04-2014, 16:59:07
hola amigos:
En una aplicación se me esta demorando un poco el proceso de escaneo (extraer TXT) e inserción de ficheros, tengo un procedimiento que escanea una carpeta y va extrayendo todo el contenido txt y luego inserto los ficheros en una base de datos. necesito me recomienden como puedo implementra hilos de ejecucion en ese caso y en que lugar seria la mejor forma de hacerlo.

//este es el procedimiento que recorre un árbol de directorios y me entrega los ficheros y muestra con progress
procedure TForm2.RastreaDir(dir: string);
var
FileSearch: TSearchRec;
R: integer;
s: string;
begin
ChDir(dir);
if FindFirst('*.*', FaDirectory, FileSearch) = 0 then
repeat
if ((FileSearch.Attr and FaDirectory) = FaDirectory) then
begin
application.ProcessMessages;
if (FileSearch.Name <> '.') and (FileSearch.Name <> '..') then
RastreaDir(dir + '\' + FileSearch.Name);
end
else
begin
application.ProcessMessages;
if cancelando then Exit;
PCarpeta.Progress := PCarpeta.Progress + 1;PCarpeta.Refresh;
LFichero.Caption := FileSearch.Name; LFichero.Refresh;
s := CaminoCompleto(dir + '\' + FileSearch.Name);
if DataModule1.ExisteFichero(FileSearch.Name, s) then
begin
if smessagedlg('Organizador Electrónico',
'El fichero ' + FileSearch.Name +
' existe en la base de datos desea sobreescribirlo ? ',
mtInformation, [mbYes, mbno], 1) = mrYes then
AgregaFichero(dir + '\' + FileSearch.Name);
end
else
AgregaFichero(dir + '\' + FileSearch.Name);
end;
if cancelando then Exit;
until FindNext(FileSearch) <> 0;
FindClose(FileSearch);
end;

// y este es el de agregar los ficheros
procedure TForm2.AgregaFichero(n: string);
var
File1: TFileStream;
q: Tsqlquery;
pag, s: string;
idcarpeta, idfichero, idpadre: integer;
PosS: integer;
ins: boolean;
begin
if not cancelando then
begin
Memo1.Lines.Clear;
lEjecuta.Caption := 'Extrallendo texto...'; lEjecuta.Refresh;

LFichero.Caption := 'Fichero: ' + ExtractFileName(n); LFichero.Refresh;

LCarpeta.Caption := rightstr(ExtractFilePath(n), Length(ExtractFilePath(n)) - Length(CarpetaRaiz)); LCarpeta.Refresh;
application.ProcessMessages;

idcarpeta := InsertaCarpetas(n); //este procedimiento inserta en sqlite todas las carpetas en la estructura en que aparecen en la base de datos

if idcarpeta <> -1 then
begin
try
ExtraeTexto(n, pag);
except
Memo1.Lines.Clear;
pag:='1';
end;

InsertaFichero(n, idfichero);// este inserta el fichero en sqlite
InsertaNombre(n, pag, idfichero, idcarpeta, '');//este inserta el nombre del fichero con el respectivo id_fichero e id_carpeta
end;
end;
LiberarMemoria;// limpia memoria si se quedo algo en el proceso de sacar el texto de pdf etc.
end;



quisiera saber que sugerencia me dan y en que lugar se debiera implementar.

gracias juan

radenf
07-04-2014, 23:17:15
Estimado juank1971:

No te diré donde es mejor utilizar utilizar hilos de ejecución, pero te contaré mi experiencia.
También tenía procesos que enlentecían mi programa y generaban unas esperas eternas y lo solucioné justamente utilizando los threads. Intenté crear los threads con el ThreadObject que trae Delphi y no logré jamás hacerlos funcionar (Yo soy menos que novato). Instalé los componentes TBMDThreadSet de Mitov, que son gratuitos y se pueden descargar de este link (http://www.mitov.com/free_downloads) y me solucionaron todos los problemas.
Yo incluí los procesos que enlentecían la aplicación en el BMDThreadExecute y los llamo con BMDThread1.Start. Puedo asignarle acciones en los eventos Start, Terminate y Update y unir varios threads con el TBMDThreadGroup que incluyen estos componentes.
Te quiero señalar además que el uso de Application.ProcessMessages si bien permite la fluidez de algunos procesos, en mi caso la mayoría de las veces los hacían más lentos y luego de leer este artículo (http://delphi.about.com/od/objectpascalide/a/delphi-processmessages-dark-side.htm) me decidí a eliminar la mayoría de ellos y dejar sólo los que consideré indispensables.
Espero haber sido de alguna ayuda.

Salu2

Neftali [Germán.Estévez]
08-04-2014, 11:15:36
Los que comentas son típicos procesos para añadir dentro de Threads, puesto que a priori (si no he entendido mal) el programa no debe esperar a que estos acaben para continuar trabajando, sino que pueden "lanzarlos" en un segundo plano.
Yo dividiría en dos, por un lado en que extrae los TXT y por otro el que los inserta en Base de Datos (incluso podrían estar funcionando en paralelo -tipo producer/consumer-).

Ten en cuenta para el de base de datos que deberás crear conexiones especificas para el hilo (Base de Datos), no puedes compartir las del programa principal.

Por lo demás, si necesitas que seamos más concretos ya dirás.

juank1971
09-04-2014, 15:49:46
ok, gracias por la ayuda, pero todavía tengo mis dudas es una estructura de árbol es la misma de windows llevándola a base de datos, pero el escaneo de los txt esta asociada un fichero, no veo como escanear texto sin esperar a que termine y me de el txt para insertarlo luego junto a lo demás, me explico mas:

Son la típica estructura de árbol que está en windows y voy a llevarla a base de datos sqlite.
\nueva carpeta\fichero.pdf
\nueva carpeta\otra carpeta\fichero1.pdf
\nueva carpeta\otra carpeta\fichero2.pdf.......

esta estructura en sqlite es las tablas :
carpetas (Id_carpeta ,id_padre,Nombre,Descripcion) //estructura de diretorios
ficheros (Id_fichero,fichero) // guarda el fichero como tal
nombres(Id_nombre,Nombre,Descripcion,Id_fichero,id_carpeta,Paginas,fecha)// guarda los nombres
contenido(id_fichero,contenidoTXT)// guarda el contenido txt del fichero en ese tabla con la facilidad (Full Text Shearch ) para hacer rapida las busquedas

entonces no logro ver los hilos independiente ya que en un mismo fichero todo el proceso , ahora estaba viendo lo de tdirectory que creo tengo todo en una lista y me parece que no tengo que hacer recursivo.
pero no se si sera exagerado crear un hilo para cada fichero o sea un hilo para "\nueva carpeta\otra carpeta\fichero1.pdf " y que el hilo se encarga de escanear el txt cuando lo tenga insertar de la base de datos.

otra cosa el proceso de insertar no lo veo tampoco muy separado al menos de un mismo fichero porque una tabla necesita el id devuelto para asociarlo con la otra como tampoco veo separado el de txt porque necesito el resultado del texto para insertarlo en las bases luego.

yo creo que ni yo mismo me entiendo.. ja.

voy a explorar con tdirectory a ver.

Neftali [Germán.Estévez]
09-04-2014, 16:52:55
Estaba pensando que primero hacías una pasada por los ficheros para extraer el texto y guardarlo en un fichero (TXT) y luego en una segunda pasada cogías todos esos ficheros y los insertabas en Base de Datos.
Me da la impresión (por lo que entiendo ahora) que no lo haces así, sino que lo vas haciendo al mismo tiempo.

En ese caso hay 2 opciones:
(1) Separar y hacer 2 threads; Me parece más modular, pero se aleja de lo que tienes ahora y debes programar más.
(2) Hacer un único thread que haga lo que ahora; recorra ficheros, extraiga e inserte en Base de Datos. En este caso el thread es más complejo.

No hagas un thread por fichero. mucha complejidad y mucha sobrecarga.