sábado, 5 de marzo de 2011

Hilos en Power Builder??

 Una de las cosas que me gusto cuando programe en C++ era la facilidad de trabajar con hilos. Con ello, sumado a los punteros, conseguía crear clases que sus instancia podían tener "vida" propia. Paso el tiempo( no mucho por cierto), empece a desarrollar en power builder, un lenguaje muy potente para realizar reportes, y trabajar con los diferentes Motores de Base de Datos. Pero no tenia punteros, ni trabajar con los pixeles ( al menos no lo he visto hasta el día de hoy). Otras de las cosas que no encontré fueron los hilos.

Por cosas de la vida, el principal desarrollo que realizamos en la empresa esta en power builder. Una de las ventanas principales, por no decir la principal, cada vez tiene mayor información, en consecuencia tenia que cargar toda la data antes mostrarse al usuario. Pasaba el tiempo y esta carga se hacia mas larga y el tiempo de espera para el usuario era mayor. Se llego a un punto en que se pensaba que el sistema se colgaba por completo.
Ya no se podía seguir así, se necesitaba  un segundo proceso que realice el trabajo pesado paralelamente al principal. Solución???? hilos!! pero power no tiene hilos (en verdad no lo tiene).
Me metí al Internet a buscar información, me canse de buscar no encontré mucho y lo poquito que encontré estaba en ingles, tenia que leer con el diccionario al costado jejeje.
Mi jefe me habilito un ejemplo del mismo SyBase, funcionaba, pero yo no entendía como. me demore cerca de dos días en revisarlo, probarlo y modificarlo. Despues de esto llegue a la conclusión que power builder no   trabaja con hilos. Se implemento en el sistema, y ahora  la pantalla se muestra al usuario con interacción, mientras el segundo proceso esta cargando la información sin dar la apariencia de que el sistema este colgado.



Power Buider Intenta simular hilos,  para ello ejecuta otra aplicación con la cual se comunica a través de un objeto conector. diagramando seria así.


Como podemos observar son dos programas corriendo, esto implica desde la aplicación secundaria no podemos manipular los controles ni las variables de la aplicación principal, el único que puede realizar ello es el objeto conector.

Para que se entienda mejor, realizare una aplicación de ejemplo.

creamos, el workspace con nombre "hilo", la aplicación también del mismo nombre, creamos una ventana llamada w_principal con 3 cajas de texto y 4 botones. ademas creamos 2 objetos de tipo "custom class"
llamados "comunicador" (hará de conector) e "hilo_"(sera la aplicación secundaria). Después de esto obtendrán algo como esto:


abrimos el objeto "comunicador", declaramos una variable de instancia de tipo "singlelineedit" con nombre "sle", esta variable permitira manipular la caja de texto cuando el proceso en segundo plano termine

                singlelineedit sle

luego creamos la función "establecer" con un parámetro de tipo   "singlelineedit" con nombre "sle_", esta función establecerá que caja de texto vamos a manipular. en la función escribimos la siguiente linea de código
              
                sle=sle_

en el mismo objeto creamos la función "insertar" con un parámetro de tipo "long" con nombre "argumento". Esta función escribirá el resultado entregado por el segundo proceso.en la función escribimos la siguiente linea de código.

                sle.text=string(argumento)


Ahora abrimos el objeto "hilo_" y creamos  la función "calcular"  con un parámetro de tipo "comunicador" con nombre "comunica". Esta función sera la que este corriendo en segundo plano, como este post solo es ejemplo, esta función solo contara. En la función escribimos las siguientes lineas de código.


                                 long i
                        sleep(3)
                                for i=0 to 100000000
                                next
                                comunica.insertar(i)

observamos que cuando termina el bucle llama a la función, del objeto conector, que escribirá en la caja de texto.

Por cuestiones didácticas,  creemos un evento llamado también "calcular"  con parámetro de tipo "comunicador" con nombre "comunica". En el evento escribimos el siguiente código

                           long i
                  sleep(3)
                          for i=0 to 100000002
                          next
                         comunica.insertar(i).

Observamos este evento que prácticamente hace lo mismo que la función, como mencione lineas arriba, es por cuestiones didácticas.

Ahora vamos a la venta principal "w_principal"  declaramos variables de instancia a los objetos a utilizar

                 comunicador comunicador1 , comunicador2
                 hilo_ hilo1, hilo2

y en el envento click del boton que tiene como etiqueta "hilo1" escribimos los siguiente.


             comunicador1 = create comunicador
              hilo1= create hilo_
             comunicador1.establecer(sle_1)
            sle_1.text="hilo1 evento Procesando, espere"

              SharedObjectRegister("hilo_", "hilo1") 
            SharedObjectGet("hilo1",hilo1)
          hilo1.post event calcular(comunicador1)
           SharedObjectUnRegister('hilo1') 

Aquí primero creamos los objetos , luego decimos al objeto conector que va a escribir en la primera caja, luego en dicha caja aparecerá un mensaje para el usuario, luego power registra el objeto, lo llama, y ejecuta el evento como evento post por ultimo lo libera del registro.


 en el envento click del boton que tiene como etiqueta "hilo 2" escribimos los siguiente.


             comunicador2 = create comunicador
              hilo2= create hilo_
              comunicador2.establecer(sle_2)
              sle_2.text="hilo2 funcion Procesando, espere"

              SharedObjectRegister("hilo_", "hilo2") 
             SharedObjectGet("hilo2",hilo2)
            hilo2.post   calcular(comunicador2)
         SharedObjectUnRegister('hilo2') 

la diferencia entre este boton y el otro es que uno llama al evento y el otro llama a la función, con cualquiera de las dos formas se puede realizar, eso queda a criterio de cada uno

el tercer boton "2 hilos corriendo"  ejecuta los dos hilos a la vez

              comunicador1 = create comunicador
               hilo1= create hilo_
              comunicador1.establecer(sle_1)
               sle_1.text="hilo1 evento Procesando, espere"

                    SharedObjectRegister("hilo_", "hilo1") 
                   SharedObjectGet("hilo1",hilo1)
                   hilo1.post event calcular(comunicador1)
                  SharedObjectUnRegister('hilo1') 


                    comunicador2 = create comunicador
                     hilo2= create hilo_
                    comunicador2.establecer(sle_2)
                      sle_2.text="hilo2 funcion Procesando, espere"

                           SharedObjectRegister("hilo_", "hilo2") 
                       SharedObjectGet("hilo2",hilo2)
                      hilo2.post   calcular(comunicador2)
                    SharedObjectUnRegister('hilo2') 

El ultimo boton "sin hilo", corre el mismo proceso pero en la ventana principal, esto es con el fin de poder observar como se "cuelga el programa". escribimos los siguiente


                              long i
                  sleep(3)
                        for i=0 to 100000000
                           next
                         sle_3.text=string(i)


Este programita esta corriendo. aquí muestro imagen de lo que aparecerá.

                        Resultado





Espero que les haya servido, y no padezcan todo lo que yo.... Al final siempre es bueno darse la mano. 
Cualquier duda sugerencia, o algo que me haya equivocado hacerla llegar.

 Gracias.... 



7 comentarios:

  1. Es muy interesanto, pero dime como puedo hacer una aplicación que uses la programación en pararelo. Osea que mi aplicación en powerbuilder consuma 2 o más microprocesadores y no solo uno

    ResponderEliminar
  2. Hola daniel, hasta donde pude averiguar, power solo puede simular hilos. Esto implica que es imposible que pueda controlar a mas de un procesador para el procesamiento paralelo. Dependiendo de tu propocito(que deseas hacer??), puedes usar el sistema distribuido con el EAServer. Pero si quiere manejar mas de un procesador sin importar el lenguaje tienes que usar a nuestro viejo amigo C.

    ResponderEliminar
  3. Que tal? Como harías para traer datos en Background, es decir por ejemplo hacer un retrieve, e ir mostrando las filas en pantalla a medida que los va trayendo?

    ResponderEliminar
    Respuestas
    1. Hola David, como se menciona en el post el problema mio era que teníamos que consolidar mucha data antes de mostrarla al usuario, esto tomaba mucho tiempo dando la apariencia de que el sistema se había colgado. lo que se hizo fue que el proceso secundario consolide esta informacion y que a traves de un cursor vaya extrayendo la data que luego la envia al proceso principal a traves del objeto conector. Para nuestro caso fue un objeto arbol, en tu (caso puede ser un Data windows). El usuario final observo la pantalla y poco a poco el arbol se llenaba de información.

      Eliminar
    2. Claro, imaginé que era con un Cursor, voy a probarlo. Muchas Gracias

      Eliminar
  4. Este comentario ha sido eliminado por el autor.

    ResponderEliminar