PDA

Ver la Versión Completa : Formulario con threads


Ramsay
25-01-2016, 16:00:28
Hola , eh observado siempre de aplicaciones en delphi que realizan muchas tareas y nunca se tildan ni esperan , osea que los demas controles del formulario se pueden usar , en mi caso , siempre se tildan mis programas como 3 segundos hasta que termine la tarea , ¿ como hacen esos programadores ? ¿ usan threads por cada boton ?

Osorio
25-01-2016, 16:36:25
Una buena practica que se usa para realizar procesos que demanden bastante consumo de recursos y/o bastante tiempo en ejecución se tiende a ejecutarlo a traves de un hilo para evitar que la intefaz grafica aparente estar congelada mientras se ejecuta dicho proceso.

pasate por google y escribe "hilos delphi site:www.clubdelphi.com" y veras como te salen varias opciones bastante descriptivas.

Si te aparece alguna duda especifica aca estaremos.

Saludos.

Neftali [Germán.Estévez]
25-01-2016, 17:29:14
en mi caso , siempre se tildan mis programas como 3 segundos hasta que termine la tarea , ¿ como hacen esos programadores ? ¿ usan threads por cada boton ?

Yo no generalizaría, ya que hay tareas que son fácilmente implementables dentro de un thread, pero en cambio otras lo serán difícilmente.
Deberias explicar, cuales son esas tareas antes de probar a moverlas a un thread.

Ñuño Martínez
25-01-2016, 20:33:32
Por otro lado, el objeto Application posee el método ProcessMessages (http://delphi.about.com/od/objectpascalide/a/delphi-processmessages-dark-side.htm). Este método procesa los mensajes del sistema operativo, de forma que puedes usarlo para evitar este tipo de bloqueos. Por ejemplo:


FOR N := 0 TO Data.NumCount DO
BEGIN
HaceAlgoConDato (Data.Elemento[N]);
{ De vez en cuando procesa mensajes para que no se cuelgue: }
IF N MOD 10 = 0 THEN Application.ProcessMessages
END;

AgustinOrtu
25-01-2016, 23:49:11
Uno no implementa un thread para un boton, implementa metodos y luego esos metodos los ejecuta en segundo plano (en background) en otro(s) hilo(s) de ejecucion, para que el hilo principal que controla la interfaz pueda seguir haciendo su trabajo

Usar Application.ProcessMessages para mi es como poner un goto; lo siento pero creo que es ahogarse en un vaso de agua. La forma de resolver estos problemas es usando threads; y si, es dificil, muy dificil, es un arte. Por eso es que siempre se insiste en escribir codigo desacoplado, sobre todo desacoplado de la VCL; los procesos de negocio deberian poder funcionar en una aplicacion de consola

Si se escribe codigo de esta manera, pasarlo a multi-thread es mucho mas facil, mucho mas natural y mucho mas poderoso (mas rapido y eficiente a la hora de usar recursos)

Un buen sitio para aprender multi-thread con delphi es el de Primoz Gabrijelcic:

Revisa su blog (http://www.thedelphigeek.com/), sobre todo la parte de presentaciones (http://www.thedelphigeek.com/p/presentations.html)

Este es su sitio web personal (http://primoz.gabrijelcic.org/), donde tambien demuestra como usar la nueva unidad System.Threading que se incluye a partir de XE 7

Y por ultimo hay varios replays de CodeRage en Youtube donde tambien se muestran tecnicas muy interesantes

Ramsay
26-01-2016, 00:01:58
hola , les agradezco las respuestas , los threads son para cargar paginas en idhttp , escanear puertos , y buscadores de archivos.
una pregunta , ¿ entonces lo que tengo que hacer es crear un timer por boton usando Application.ProcessMessages ?

Neftali [Germán.Estévez]
26-01-2016, 08:56:01
los threads son para cargar paginas en idhttp , escanear puertos , y buscadores de archivos.
¿ entonces lo que tengo que hacer es crear un timer por boton usando Application.ProcessMessages ?

Vale, un poco mejor.
Para las questiones que comentas puedes utilizar "sin problemas" threads.
Es cuestión de empezar a ver cómo funcionan y luego aplicarlos.

Si lees un poco de documentación, verás que siguiendo algunas normas sencillas, y con un poco de práctica no son tan difíciles como a priori parecen.

¿ entonces lo que tengo que hacer es crear un timer por boton usando Application.ProcessMessages ?

El Application.ProcessMessages se utiliza normalmente dentro de bucles para "dar tiempo al sistema" a realizar otras tareas y así que no parezca que el sistema de detiene.
Por ejemplo, si utilizas un código como este:


for i:=0 to 100000 do begin
label.Caption := IntToStr(i);
end;


Verás que durante su ejecución el sistema se detiene y queda "congelado"; Simplemente es porque durante mientras ejecuta este código, el sistema no se detiene a atender a otras tareas como los mensajes que llegan del ratón o redibujar elementos de pantalla; Eso da la impresión que el sistema se "tilda" como tu comentas.

Si lo cambias por este:


for i:=0 to 100000 do begin
label.Caption := IntToStr(i);
Application.ProcessMessages;
end;


Entonces lo que le decimos al sistema es que cuando llega al "Application.ProcessMessages" justamente haga eso. Durante un instate se dedique a procesar otros mensajes que le lleguen (de ahí lo de "procesar Mensajes"). Eso provoca que la aplicación no se "bloquee" (o no de esa impresión).

Hay que decir que el ProcessMessages no siempre es la solución.
Hay casos, por ejemplo, si realizamos una petición a un FTP, a un WebService, ejecutamos una consulta,... en que no podemos utilizarlo, simplemente porque no tenemos ningún bucle donde colocarlo. En esos casos, es en los que los threads nos pueden ayudar (el tema de Base de Datos es algo más complejo (http://neftali.clubdelphi.com/?p=883)).

Este ejemplo, habla de realizar peticiones utilizando las Indy mediante Threads. (http://neftali.clubdelphi.com/?p=3572)
Aquí, un par de ejemplos sencillos sobre threads, adecuados para empezar (ej1 (http://neftali.clubdelphi.com/?p=146), ej2 (http://neftali.clubdelphi.com/?p=149)).

Un saludo.

Ñuño Martínez
26-01-2016, 10:45:36
Usar Application.ProcessMessages para mi es como poner un goto; lo siento pero creo que es ahogarse en un vaso de agua. La forma de resolver estos problemas es usando threads; y si, es dificil, muy dificil, es un arte. Por eso es que siempre se insiste en escribir codigo desacoplado, sobre todo desacoplado de la VCL; los procesos de negocio deberian poder funcionar en una aplicacion de consola
No estoy de acuerdo con que sea un GOTO. Es más bien una interrupción. De hecho, siempre puedes añadir un evento en tu lógica de negocio para este tipo casos y otros. Es más, yo recomiendo un evento "onIddle" o un "onUpdate" (o ambos, aparte de un "onStart", "onFinished", etc.) en procesos que se sabe que pueden llevar su tiempo. Luego los usas o no según quieras o necesites.

Lepe
26-01-2016, 19:37:13
También los eventos "OnShow", "OnActivate", "OnPaint" de las ventanas, hay que usarlo lo mínimo posible, con "código rápido".

Saludos!

Ramsay
27-01-2016, 00:46:52
Genial , el multi threading es todo un tema , es bien avanzado , me va gustar estudiarlo , ¿ que es mas rapido o cual se nota mas rapido o se tilda menos en la aplicacion usar "Application.ProcessMessages" o hacer multithreading ?

AgustinOrtu
27-01-2016, 01:04:51
Vuelvo a reiterar: Application.ProcessMessages no es programacion multi-hilo. No evita que tu programa se bloquee

Es un HACK (si, mayuscula, subrayado y negrita), es analogicamente comparable a una instruccion goto, a herencia multiple, etc.


En el único caso en el que te puede llegar a ayudar en algo (escribo esto muy a mi pesar..) es en un bucle que tarda mucho en ejecutarse (llamemosle tiempo total) pero que cada iteracion es razonablemente rapida

Por que? Considera este codigo (exagerado)


for i := 1 to 100000000000000000 do
begin
j := j + i;
end;


Si se ejecuta ese fragmento de codigo en un evento OnClick de un boton, hasta que no termina de ejecutarse la aplicacion esta tildada.


for i := 1 to 100000000000000000 do
begin
j := j + i;
Application.ProcessMessages;
end;


El mismo codigo, pero ahora agregamos la linea magica al final del bucle. El hecho de sumar dos numeros es una operacion muy rapida, obviamente hacerla trillones de veces va a demorar algun tiempo; pero cada una sola operacion es rapida. Entonces, sumo un numero y luego proceso los mensajes que recibio la aplicacion; en este caso la aplicacion no va a parecer tildada

Ahora considera este codigo:


Sleep(5000); // se duerme 5 segundos


Ja! ahi no tenes quien te salve. Donde pones el ProcessMessages?

Lo que te quiero decir es lo que comento mas arriba German: Si queres llamar procesos, o calcular valores intermedios que tardan cierto tiempo, abrir un query, etc; el ProcessMessages no te puede ayudar

Entonces lo ideal es aprender a utilizar threads. Es cierto, es muy dificil, pero para la gran mayoria de las tareas, si programamos bien, es relativamente sencillo

Sobre todo con las bibliotecas que he comentado mas arriba. Omni implementa el Async.Await que todos los chicos de .NET adoran; la System.Threading de XE7 tambien lo vuelve relativamente sencillo.

Y aunque dependas pura y exclusivamente de la clase TThread, tampoco es tan complicado

Tambien recorda que esta este foro para ayudarte

Yo creo que cuanto antes te subas al barco del multi-thread, mejor: adaptar un programa grande mas adelante para convertirlo en multi-hilo puede ser un hueso muy duro de roer. Y guste o no, es el futuro de la programacion. De nada sirve que la gente gaste dinero en procesadores multi-core si nosotros los programadores no los aprovechamos

AgustinOrtu
27-01-2016, 01:20:34
Este enlace (http://delphi.about.com/od/objectpascalide/a/delphi-processmessages-dark-side.htm), en realidad ese sitio, tienen muy buena informacion

Tambien tiene ejemplos donde el ProcessMessages te puede ocasionar problemas

Neftali [Germán.Estévez]
27-01-2016, 10:52:57
¿ que es mas rapido o cual se nota mas rapido o se tilda menos en la aplicacion usar "Application.ProcessMessages" o hacer multithreading ?

Mucho más rápido "Application.ProcessMessages". Lo pones y ya está... :p:p:p

Hablando en serio... Creo que ya lo han comentado. Es que no es lo uno o lo otro. No tienen nada que ver y no se usan para las mismas cosas. No es que puedas escoger entre lo uno o lo otro.

(1) "Application.ProcessMessages" simplemente se pone en un lugar del programa para dar tiempo a procesar mensajes.
(2) Usar threads, significa que programas un proceso completo de tu aplicación en un hilo diferente.

Los threads son para una cosa, el "Application.ProcessMessages" para otra.

los threads son para cargar paginas en idhttp , escanear puertos , y buscadores de archivos.


Para el primero y el segundo debes utilizar threads, por muchos "Application.ProcessMessages" que pongas no van a servir de nada.
En el caso del tercero, no opino, porque no se exactamente a qué te estás refiriendo.

Casimiro Notevi
27-01-2016, 11:51:45
por muchos "Application.ProcessMessages" que pongas no van a servir de nada. Si que sirve, para que vaya muchísimo más lento que si no se pusiera :)

Neftali [Germán.Estévez]
27-01-2016, 16:46:13
Si que sirve, para que vaya muchísimo más lento que si no se pusiera :)


Cierto...
:D:D:D

Ramsay
27-01-2016, 19:16:06
Otra duda sobre el tema , seria que por ejemplo un formulario tengo dos botones , uno empieza una funcion larga , el otro boton para todo el proceso del boton uno , como los botones empezar y parar , pense que seria facil , solo meto la funcion larga en el primero boton en un timer y le activo para despues parar el timer desde el segundo boton , pero el problema es que no sabria ignorar el timeout del timer , ya que se ejecutaria cada 1 segundo lo mismo , ¿ como se hace realmente ?

Casimiro Notevi
27-01-2016, 19:49:07
Creo que quieres matar moscas a cañonazos.
Lo primero de todo es saber el motivo de que vaya lenta tu aplicación, que por cierto, no has dicho nada de cuál es el problema que tienes realmente.
Luego habrá que buscar soluciones.
Pero si se pincha la rueda del coche, la solución no es esta:

http://www.subeimagenes.com/img/cocheburro-1618412.jpg