Ejemplos de FoxCore

Los siguientes ejemplos muestran cómo implementar diferentes funcionalidades con FoxCore para procesamiento paralelo y multitarea. Puedes usar estos ejemplos como punto de partida para tus propios proyectos.

Ejemplo 1: Tarea básica con eventos

Este ejemplo muestra cómo crear y ejecutar una tarea básica, y cómo manejar eventos para responder cuando la tarea se complete o falle.

* Cargar FoxCore
DO "ruta\a\FoxCore-VFP9-v1.0.app"

_screen.FoxCore.SetTimeout(50)
* Definir el script a ejecutar
TEXT TO lcScript NOSHOW
   FOR i = 1 TO 5
      WAIT WINDOW "Procesando " + STR(i) + " de 5..." TIMEOUT 1
   ENDFOR
   RETURN "Proceso completado exitosamente"
ENDTEXT

* Crear y configurar la tarea
PUBLIC loTask, loHandler
loTask = _screen.FoxCore.NewTask(lcScript)

* Instanciar el manejador y vincular eventos
loHandler = CREATEOBJECT("TaskHandler")
loTask.AddEventListener("OnComplete", loHandler, "OnTaskComplete")
loTask.AddEventListener("OnFailed", loHandler, "OnTaskFailed")
loTask.AddEventListener("OnCancelled", loHandler, "OnTaskCancelled")
loTask.AddEventListener("OnTimedOut", loHandler, "OnTaskTimedOut")

loTask.Run()

* Definir los manejadores de eventos
DEFINE CLASS TaskHandler AS CUSTOM
    PROCEDURE OnTaskComplete(toTask AS Task, tvResult AS Variant)
        ?"Tarea completada: " + tvResult
    ENDPROC
    
    PROCEDURE OnTaskFailed(toTask AS Task, tcError AS String)
        ?"Error: " + tcError
    ENDPROC
    
    PROCEDURE OnTaskCancelled(toTask AS Task, tcMessage AS String)
        ?"Tarea cancelada: " + tcMessage
    ENDPROC

    PROCEDURE OnTaskTimedOut(toTask AS Task, tcMessage AS String)
        ?"Tarea expirada: " + tcMessage
    ENDPROC
ENDDEFINE

Explicación:

  1. Cargamos FoxCore con DO "ruta\a\FoxCore-VFP9-v1.0.app".
  2. Establecemos un timeout de 50 segundos para las tareas.
  3. Definimos un script que muestra ventanas de espera y retorna un mensaje.
  4. Creamos una nueva tarea con _screen.FoxCore.NewTask(lcScript).
  5. Creamos un manejador de eventos y lo vinculamos a los eventos de la tarea.
  6. Ejecutamos la tarea con loTask.Run().
  7. Definimos una clase con métodos para manejar los diferentes eventos de la tarea.

Ejemplo 2: Múltiples tareas en paralelo

Este ejemplo muestra cómo ejecutar múltiples tareas en paralelo y esperar a que todas se completen.

* Cargar FoxCore
DO "ruta\a\FoxCore-VFP9-v1.0.app"

* Crear varios scripts para ejecutar en paralelo
LOCAL ARRAY laScripts[3]
TEXT TO laScripts[1] NOSHOW
    * Tarea 1: Procesar archivos
    LOCAL i
    FOR i=1 TO 3
        WAIT WINDOW "Procesando archivo " + TRANSFORM(i) + "..." TIMEOUT 2
    NEXT
    RETURN "Tarea 1 completada"
ENDTEXT

TEXT TO laScripts[2] NOSHOW
    * Tarea 2: Hacer cálculos
    LOCAL j
    j = 0
    FOR i = 1 TO 1000000
        j = j + 1
    NEXT
    RETURN "Tarea 2 completada"
ENDTEXT

TEXT TO laScripts[3] NOSHOW
    * Tarea 3: Simular conexión a red
    WAIT WINDOW "Conectando..." TIMEOUT 2
    WAIT WINDOW "Descargando datos..." TIMEOUT 3
    RETURN "Tarea 3 completada"
ENDTEXT

* Ejecutar todas las tareas en paralelo
PUBLIC loHandler, loTasks
loHandler = CREATEOBJECT("MultiTaskHandler", ALEN(laScripts))
loTasks = _screen.FoxCore.RunMultiple(@laScripts)

* Vincular eventos para cada tarea
_screen.FoxCore.AddEventListener("OnTaskComplete", loHandler, "OnTaskComplete")
_screen.FoxCore.AddEventListener("OnTaskFailed", loHandler, "OnTaskFailed")

* Esperar que todas las tareas terminen (con timeout de 30 segundos)
IF !_screen.FoxCore.WaitAll(loTasks, 60)
    ? "¡Timeout! No todas las tareas pudieron completarse"
ENDIF

FOR EACH loTask IN loTasks
    ? "Estado Tarea: ", loTask.GetStatus()
NEXT

? "Ejemplo terminado"

* Crear manejador de eventos para múltiples tareas
DEFINE CLASS MultiTaskHandler AS CUSTOM
    PROTECTED nCompletedTasks
    PROTECTED nTotalTasks
    
    PROCEDURE INIT(tnTotalTasks)
        THIS.nCompletedTasks = 0
        THIS.nTotalTasks = tnTotalTasks
    ENDPROC
    
    PROCEDURE OnTaskComplete(toTask, tvResult)
        THIS.nCompletedTasks = THIS.nCompletedTasks + 1
        ? "Tarea " + toTask.GetTaskId() + " completada: " + TRANSFORM(tvResult)
        
        IF THIS.nCompletedTasks == THIS.nTotalTasks
            ? "¡Todas las tareas completadas!"
        ENDIF
    ENDPROC
    
    PROCEDURE OnTaskFailed(toTask, tcError)
        ? "Error en la tarea " + toTask.GetTaskId() + ": " + tcError
    ENDPROC
ENDDEFINE

Explicación:

  1. Definimos tres scripts diferentes para ejecutar en paralelo.
  2. Creamos un manejador de eventos que lleva un contador de tareas completadas.
  3. Ejecutamos todas las tareas en paralelo con _screen.FoxCore.RunMultiple(@laScripts).
  4. Vinculamos eventos a nivel global para todas las tareas.
  5. Esperamos a que todas las tareas terminen con _screen.FoxCore.WaitAll(loTasks, 60).
  6. Verificamos el estado de cada tarea después de la ejecución.

Ejemplo 3: Procesamiento paralelo de registros

Este ejemplo muestra cómo dividir un conjunto de registros en lotes y procesarlos en paralelo.

* Cargar FoxCore
DO "ruta\a\FoxCore-VFP9-v1.0.app"

* Procesamiento paralelo usando RunMultiple
LOCAL lnRegistros, lnTareas, lnPorTarea, i

* Contar registros totales
CLEAR
CLOSE DATABASES ALL
SELECT 0
USE C:\vconta\DATA\sucursal.dbf SHARED
SELECT COUNT(*) FROM sucursal INTO ARRAY laTotal
lnRegistros = laTotal[1]
lnTareas = 20 && Número de tareas paralelas
lnPorTarea = INT(lnRegistros / lnTareas)
_screen.FoxCore.SetTimeout(60)

* Preparar los scripts
DIMENSION laScripts[lnTareas]
FOR i=1 TO lnTareas
    * Calcular el rango para esta tarea
    LOCAL lnInicio, lnFin
    lnInicio = ((i-1) * lnPorTarea) + 1
    lnFin = IIF(i = lnTareas, lnRegistros, i * lnPorTarea)
    
    TEXT TO laScripts[i] TEXTMERGE NOSHOW
        WAIT WINDOW "Procesando rango de <> a <>" NOWAIT
        SELECT 0
        USE C:\vconta\DATA\sucursal.dbf SHARED    
        * Procesar registros del rango asignado
        SELECT * FROM sucursal WHERE BETWEEN(RECNO(), <>, <>) INTO CURSOR cursorTarea
        USE IN sucursal

        SELECT cursorTarea
        SCAN
            * Solo escribimos en un fichero log
            lcStr = "codigo:" + ALLTRIM(cursorTarea.codigo) + "población:" + ALLTRIM(cursorTarea.poblacion)
            STRTOFILE(lcStr+CHR(13)+CHR(10),"c:\a1\Task_"+gcTaskId + ".log", 1)
        ENDSCAN
        USE IN cursorTarea        
        
        RETURN "Completado rango " + TRANSFORM(lnInicio) + " a " + TRANSFORM(lnFin)
    ENDTEXT
ENDFOR

* Crear el manejador de eventos
PUBLIC loHandler, loTasks
loHandler = CREATEOBJECT("MultiTaskHandler", lnTareas)

* Ejecutar todas las tareas en paralelo
loTasks = _screen.FoxCore.RunMultiple(@laScripts)

* Vincular eventos para monitoreo
_screen.FoxCore.AddEventListener("OnTaskComplete", loHandler, "OnTaskComplete")
_screen.FoxCore.AddEventListener("OnTaskFailed", loHandler, "OnTaskFailed")

* Esperar que todas las tareas terminen (con timeout de 60 segundos)
IF !_screen.FoxCore.WaitAll(loTasks, 60)
    ? "¡Timeout! No todas las tareas pudieron completarse"
ELSE
    ? "Todas las tareas completadas. Procediendo con el siguiente paso..."    
ENDIF

* Manejador de eventos mejorado
DEFINE CLASS MultiTaskHandler AS CUSTOM
    PROTECTED nCompletedTasks
    PROTECTED nTotalTasks
    DIMENSION aResults[1]
    
    PROCEDURE INIT(tnTotalTasks)
        THIS.nCompletedTasks = 0
        THIS.nTotalTasks = tnTotalTasks
        DIMENSION THIS.aResults[tnTotalTasks]
    ENDPROC
    
    PROCEDURE OnTaskComplete(toTask, tvResult)
        THIS.nCompletedTasks = THIS.nCompletedTasks + 1
        
        * Guardar el resultado
        THIS.aResults[THIS.nCompletedTasks] = tvResult
        
        * Mostrar progreso
        ? "Progreso: " + TRANSFORM(THIS.nCompletedTasks/THIS.nTotalTasks * 100) + "%"
        ? "Tarea " + toTask.GetTaskId() + " completada: " + TRANSFORM(tvResult)
        
        IF THIS.nCompletedTasks == THIS.nTotalTasks
            ? "¡Totas las tareas completadas!"            
        ENDIF        
    ENDPROC
    
    PROCEDURE OnTaskFailed(toTask, tcError)
        ? "Error en la tarea " + toTask.GetTaskId() + ": " + tcError
    ENDPROC
    
    * Método para obtener todos los resultados
    FUNCTION GetResults
        RETURN @THIS.aResults
    ENDFUNC
ENDDEFINE

Explicación:

  1. Abrimos una tabla y contamos el número total de registros.
  2. Dividimos los registros en lotes basados en el número de tareas paralelas.
  3. Creamos un script para cada lote que procesará un rango específico de registros.
  4. Ejecutamos todas las tareas en paralelo.
  5. Monitoreamos el progreso a través de eventos y mostramos estadísticas.
  6. Esperamos a que todas las tareas terminen antes de continuar.

Este patrón es muy útil para procesar grandes conjuntos de datos, ya que aprovecha todos los núcleos del procesador para acelerar el procesamiento.

Ejemplo 4: Estadísticas del sistema

Este ejemplo muestra cómo obtener estadísticas del sistema y monitorear el rendimiento de las tareas.

* Cargar FoxCore
DO "ruta\a\FoxCore-VFP9-v1.0.app"

LOCAL loStats
lnStartTime = SECONDS()
* Ver estadísticas del sistema
loStats = _screen.FoxCore.GetSystemStats()
? "Procesadores lógicos: ", loStats.LogicalProcessors
? "Máximo de tareas: ", loStats.MaxTasks

* Preparar scripts (24 tareas)
LOCAL lnRegistros, lnTareas, lnPorTarea, i, lnWaitTimeout

* Contar registros totales
CLOSE DATABASES ALL
SELECT 0
USE C:\vconta\DATA\sucursal.dbf SHARED
SELECT COUNT(*) FROM sucursal INTO ARRAY laTotal
lnRegistros = laTotal[1]
lnTareas = 24 && Número de tareas paralelas
lnPorTarea = INT(lnRegistros / lnTareas)
lnWaitTimeout = 240
_screen.FoxCore.SetTimeout(lnWaitTimeout)

* Preparar los scripts
DIMENSION laScripts[lnTareas]
FOR i=1 TO lnTareas
    * Calcular el rango para esta tarea
    LOCAL lnInicio, lnFin
    lnInicio = ((i-1) * lnPorTarea) + 1
    lnFin = IIF(i = lnTareas, lnRegistros, i * lnPorTarea)
    
    TEXT TO laScripts[i] TEXTMERGE NOSHOW
        LOCAL lcResult
        lcResult = ""

        WAIT WINDOW "Procesando rango de <> a <>" NOWAIT
        SELECT 0
        SET SAFETY OFF
        SET DELETED ON
        SET EXCLUSIVE OFF
        USE C:\vconta\DATA\sucursal.dbf SHARED    

        * Procesar registros del rango asignado
        SELECT * FROM sucursal WHERE BETWEEN(RECNO(), <>, <>) INTO CURSOR cursorTarea
        IF _tally = 0
            STRTOFILE("No se encontraron registros en el rango "+CHR(13)+CHR(10),"c:\a1\Task_"+gcTaskId + ".log", 1)
            USE IN cursorTarea
            USE IN sucursal
            lcResult = .F.
        ELSE
            SELECT cursorTarea
            SCAN
                * Solo escribimos en un fichero log
                lcStr = "codigo:" + ALLTRIM(cursorTarea.codigo) + "población:" + ALLTRIM(cursorTarea.poblacion)
                STRTOFILE(lcStr+CHR(13)+CHR(10),"c:\a1\Task_"+gcTaskId + ".log", 1)
            ENDSCAN
            USE IN cursorTarea        
            lcResult = "Completado rango <>  a <>"
        ENDIF

        RETURN lcResult
    ENDTEXT
ENDFOR

* Crear el manejador de eventos
PUBLIC loHandler, loTasks
loHandler = CREATEOBJECT("MultiTaskHandler", lnTareas)

* Ejecutar todas las tareas en paralelo
loTasks = _screen.FoxCore.RunMultiple(@laScripts)

* Vincular eventos para monitoreo
_screen.FoxCore.AddEventListener("OnTaskComplete", loHandler, "OnTaskComplete")
_screen.FoxCore.AddEventListener("OnTaskFailed", loHandler, "OnTaskFailed")
_screen.FoxCore.AddEventListener("OnTaskTimedOut", loHandler, "OnTaskTimedOut")

* Mostrar estadísticas mientras se ejecutan las tareas
LOCAL lnInterval, lnLastUpdate
lnInterval = 2  && Actualizar cada 2 segundos
lnLastUpdate = 0

* Bucle de monitoreo
DO WHILE !_screen.FoxCore.WaitAll(loTasks, 0.1)  && Verificar cada 0.1 segundos
    IF SECONDS() - lnLastUpdate >= lnInterval
        CLEAR
        loStats = _screen.FoxCore.GetSystemStats()
        loSummary = _screen.FoxCore.GetTasksSummary()
        
        ? "=== ESTADÍSTICAS DE EJECUCIÓN ==="
        ? "Tiempo transcurrido: " + TRANSFORM(SECONDS() - lnStartTime) + " segundos"
        ? "Procesadores lógicos: " + TRANSFORM(loStats.LogicalProcessors)
        ? "Tareas activas: " + TRANSFORM(loStats.ActiveTasks) + " / " + TRANSFORM(loStats.MaxTasks)
        ? "Memoria disponible (GB): " + TRANSFORM(loStats.AvailableMemory)
        ? "Progreso general: " + TRANSFORM(_screen.FoxCore.GetProgress()) + "%"
        ? ""
        ? "=== RESUMEN DE TAREAS ==="
        ? "Total: " + TRANSFORM(loSummary.total)
        ? "Pendientes: " + TRANSFORM(loSummary.pending)
        ? "En ejecución: " + TRANSFORM(loSummary.running)
        ? "Completadas: " + TRANSFORM(loSummary.completed)
        ? "Fallidas: " + TRANSFORM(loSummary.failed)
        ? "Timeout: " + TRANSFORM(loSummary.timedout)
        ? "Canceladas: " + TRANSFORM(loSummary.cancelled)
        
        lnLastUpdate = SECONDS()
    ENDIF
ENDDO

* Mostrar estadísticas finales
CLEAR
? "=== ESTADÍSTICAS FINALES ==="
? "Tiempo total: " + TRANSFORM(SECONDS() - lnStartTime) + " segundos"
loSummary = _screen.FoxCore.GetTasksSummary()
? "Total tareas: " + TRANSFORM(loSummary.total)
? "Completadas: " + TRANSFORM(loSummary.completed)
? "Fallidas: " + TRANSFORM(loSummary.failed)
? "Timeout: " + TRANSFORM(loSummary.timedout)
? "Canceladas: " + TRANSFORM(loSummary.cancelled)

* Manejador de eventos mejorado
DEFINE CLASS MultiTaskHandler AS CUSTOM
    PROTECTED nCompletedTasks
    PROTECTED nTotalTasks
    PROTECTED nFailedTasks
    PROTECTED nTimedOutTasks
    
    PROCEDURE INIT(tnTotalTasks)
        THIS.nCompletedTasks = 0
        THIS.nTotalTasks = tnTotalTasks
        THIS.nFailedTasks = 0
        THIS.nTimedOutTasks = 0
    ENDPROC
    
    PROCEDURE OnTaskComplete(toTask, tvResult)
        THIS.nCompletedTasks = THIS.nCompletedTasks + 1
    ENDPROC
    
    PROCEDURE OnTaskFailed(toTask, tcError)
        THIS.nFailedTasks = THIS.nFailedTasks + 1
    ENDPROC
    
    PROCEDURE OnTaskTimedOut(toTask, tcMessage)
        THIS.nTimedOutTasks = THIS.nTimedOutTasks + 1
    ENDPROC
ENDDEFINE

Explicación:

  1. Obtenemos estadísticas del sistema con _screen.FoxCore.GetSystemStats().
  2. Creamos y ejecutamos múltiples tareas en paralelo.
  3. Implementamos un bucle de monitoreo que muestra estadísticas actualizadas cada 2 segundos.
  4. Utilizamos _screen.FoxCore.GetTasksSummary() para obtener información sobre el estado de todas las tareas.
  5. Mostramos estadísticas finales al terminar todas las tareas.

Este ejemplo es útil para monitorear el rendimiento y el progreso de tareas largas, especialmente cuando se procesan grandes volúmenes de datos.

Ejemplo 5: Esperar cualquier tarea (WaitAny)

Este ejemplo muestra cómo esperar a que cualquiera de las tareas se complete y procesar su resultado inmediatamente.

* Cargar FoxCore
DO "ruta\a\FoxCore-VFP9-v1.0.app"

* Crear scripts con diferentes tiempos de ejecución
LOCAL ARRAY laScripts[3]
TEXT TO laScripts[1] NOSHOW
    * Tarea lenta (5 segundos)
    WAIT WINDOW "Tarea 1 ejecutándose..." TIMEOUT 5
    RETURN "Resultado de la tarea 1 (lenta)"
ENDTEXT

TEXT TO laScripts[2] NOSHOW
    * Tarea rápida (2 segundos)
    WAIT WINDOW "Tarea 2 ejecutándose..." TIMEOUT 2
    RETURN "Resultado de la tarea 2 (rápida)"
ENDTEXT

TEXT TO laScripts[3] NOSHOW
    * Tarea media (3 segundos)
    WAIT WINDOW "Tarea 3 ejecutándose..." TIMEOUT 3
    RETURN "Resultado de la tarea 3 (media)"
ENDTEXT

* Ejecutar todas las tareas en paralelo
PUBLIC loTasks
loTasks = _screen.FoxCore.RunMultiple(@laScripts)

* Procesar resultados a medida que van completándose
LOCAL lnCompletedTasks, lnTotalTasks, lnTaskIndex
lnCompletedTasks = 0
lnTotalTasks = ALEN(laScripts)

DO WHILE lnCompletedTasks < lnTotalTasks
    * Esperar a que cualquier tarea se complete (timeout de 10 segundos)
    lnTaskIndex = _screen.FoxCore.WaitAny(@loTasks, 10)
    
    IF lnTaskIndex > 0
        * Una tarea se completó
        lnCompletedTasks = lnCompletedTasks + 1
        
        * Obtener el resultado de la tarea completada
        LOCAL lvResult
        lvResult = loTasks[lnTaskIndex].GetResult()
        
        ? "Tarea completada: " + TRANSFORM(lnTaskIndex) + " - Resultado: " + TRANSFORM(lvResult)
        ? "Tareas completadas: " + TRANSFORM(lnCompletedTasks) + " de " + TRANSFORM(lnTotalTasks)
        
        * Procesar el resultado inmediatamente
        DO CASE
            CASE lnTaskIndex = 1
                ? "Procesando resultado de la tarea lenta..."
            CASE lnTaskIndex = 2
                ? "Procesando resultado de la tarea rápida..."
            CASE lnTaskIndex = 3
                ? "Procesando resultado de la tarea media..."
        ENDCASE
    ELSE
        * Timeout - ninguna tarea se completó en el tiempo especificado
        ? "Timeout esperando tareas. Verificando estados..."
        
        FOR i = 1 TO lnTotalTasks
            ? "Tarea " + TRANSFORM(i) + " estado: " + loTasks[i].GetStatus()
        NEXT
    ENDIF
ENDDO

? "Todas las tareas han sido procesadas."

Explicación:

  1. Creamos tres tareas con diferentes tiempos de ejecución.
  2. Ejecutamos todas las tareas en paralelo.
  3. Utilizamos _screen.FoxCore.WaitAny(@loTasks, 10) para esperar a que cualquier tarea se complete.
  4. Procesamos cada resultado inmediatamente después de que una tarea se complete.
  5. Continuamos hasta que todas las tareas se hayan completado.

Este patrón es útil cuando necesitas procesar resultados tan pronto como estén disponibles, sin esperar a que todas las tareas terminen.

Ejemplo 6: Pasar variables a una tarea

Este ejemplo muestra cómo pasar variables a una tarea para personalizar su comportamiento.

* Cargar FoxCore
DO "ruta\a\FoxCore-VFP9-v1.0.app"

* Definir variables que queremos pasar a la tarea
LOCAL lcRuta, lnNumeroArchivos, lcPrefijo
lcRuta = "C:\datos\"
lnNumeroArchivos = 5
lcPrefijo = "archivo_"

* Definir el script que utilizará las variables pasadas
TEXT TO lcScript NOSHOW
    * Las variables lcRuta, lnNumeroArchivos y lcPrefijo estarán disponibles aquí
    LOCAL i, lcNombreArchivo, lcContenido
    
    * Crear archivos de prueba
    FOR i = 1 TO lnNumeroArchivos
        lcNombreArchivo = lcRuta + lcPrefijo + TRANSFORM(i) + ".txt"
        lcContenido = "Este es el contenido del archivo " + TRANSFORM(i)
        
        * Mostrar progreso
        WAIT WINDOW "Creando archivo " + lcNombreArchivo + "..." TIMEOUT 1
        
        * Crear el archivo
        STRTOFILE(lcContenido, lcNombreArchivo)
    ENDFOR
    
    RETURN "Se crearon " + TRANSFORM(lnNumeroArchivos) + " archivos en " + lcRuta
ENDTEXT

* Crear la tarea y pasar las variables
PUBLIC loTask
loTask = _screen.FoxCore.NewTask(lcScript)

* Pasar las variables a la tarea
loTask.SetVariable("lcRuta", lcRuta)
loTask.SetVariable("lnNumeroArchivos", lnNumeroArchivos)
loTask.SetVariable("lcPrefijo", lcPrefijo)

* Configurar manejador de eventos
LOCAL loHandler
loHandler = CREATEOBJECT("TaskHandler")
loTask.AddEventListener("OnComplete", loHandler, "OnTaskComplete")
loTask.AddEventListener("OnFailed", loHandler, "OnTaskFailed")

* Ejecutar la tarea
loTask.Run()

* Esperar a que termine (con timeout de 30 segundos)
IF loTask.Wait(30)
    ? "Tarea completada con éxito"
ELSE
    ? "La tarea no se completó en el tiempo especificado"
ENDIF

* Manejador de eventos
DEFINE CLASS TaskHandler AS CUSTOM
    PROCEDURE OnTaskComplete(toTask, tvResult)
        ? "Resultado: " + tvResult
    ENDPROC
    
    PROCEDURE OnTaskFailed(toTask, tcError)
        ? "Error: " + tcError
    ENDPROC
ENDDEFINE

Explicación:

  1. Definimos variables locales que queremos pasar a la tarea.
  2. Creamos un script que utiliza estas variables para crear archivos.
  3. Utilizamos loTask.SetVariable() para pasar cada variable a la tarea.
  4. Las variables estarán disponibles en el contexto de ejecución de la tarea.
  5. Esto permite personalizar el comportamiento de la tarea sin modificar su código.

Esta técnica es muy útil para reutilizar scripts de tareas con diferentes parámetros.

Ejemplo 7: Pasar variables complejas

Este ejemplo muestra cómo pasar objetos y arrays a una tarea.

* Cargar FoxCore
DO "ruta\a\FoxCore-VFP9-v1.0.app"

* Crear un array para pasar a la tarea
LOCAL ARRAY laClientes[3,2]
laClientes[1,1] = "001"
laClientes[1,2] = "Juan Pérez"
laClientes[2,1] = "002"
laClientes[2,2] = "María López"
laClientes[3,1] = "003"
laClientes[3,2] = "Carlos Rodríguez"

* Crear un objeto para pasar a la tarea
LOCAL loConfig
loConfig = CREATEOBJECT("Empty")
loConfig.RutaDestino = "C:\reportes\"
loConfig.FormatoFecha = "DD/MM/YYYY"
loConfig.MostrarTotales = .T.

* Definir el script que utilizará las variables complejas
TEXT TO lcScript NOSHOW
    * Las variables laClientes y loConfig estarán disponibles aquí
    LOCAL i, lcReporte, lcLinea
    
    * Crear el reporte
    lcReporte = ""
    lcReporte = lcReporte + "REPORTE DE CLIENTES" + CHR(13) + CHR(10)
    lcReporte = lcReporte + "Fecha: " + TRANSFORM(DATE(), loConfig.FormatoFecha) + CHR(13) + CHR(10)
    lcReporte = lcReporte + "----------------------------------------" + CHR(13) + CHR(10)
    
    * Procesar cada cliente
    FOR i = 1 TO ALEN(laClientes, 1)
        lcLinea = "ID: " + laClientes[i,1] + " - Nombre: " + laClientes[i,2]
        lcReporte = lcReporte + lcLinea + CHR(13) + CHR(10)
        
        * Mostrar progreso
        WAIT WINDOW "Procesando cliente " + laClientes[i,2] + "..." TIMEOUT 1
    ENDFOR
    
    * Agregar totales si está configurado
    IF loConfig.MostrarTotales
        lcReporte = lcReporte + "----------------------------------------" + CHR(13) + CHR(10)
        lcReporte = lcReporte + "Total clientes: " + TRANSFORM(ALEN(laClientes, 1)) + CHR(13) + CHR(10)
    ENDIF
    
    * Guardar el reporte
    lcRutaCompleta = loConfig.RutaDestino + "reporte_clientes.txt"
    STRTOFILE(lcReporte, lcRutaCompleta)
    
    RETURN "Reporte generado en: " + lcRutaCompleta
ENDTEXT

* Crear la tarea y pasar las variables complejas
PUBLIC loTask
loTask = _screen.FoxCore.NewTask(lcScript)

* Pasar el array y el objeto a la tarea
loTask.SetVariable("laClientes", @laClientes)
loTask.SetVariable("loConfig", loConfig)

* Configurar manejador de eventos
LOCAL loHandler
loHandler = CREATEOBJECT("TaskHandler")
loTask.AddEventListener("OnComplete", loHandler, "OnTaskComplete")
loTask.AddEventListener("OnFailed", loHandler, "OnTaskFailed")

* Ejecutar la tarea
loTask.Run()

* Esperar a que termine (con timeout de 30 segundos)
IF loTask.Wait(30)
    ? "Tarea completada con éxito"
ELSE
    ? "La tarea no se completó en el tiempo especificado"
ENDIF

* Manejador de eventos
DEFINE CLASS TaskHandler AS CUSTOM
    PROCEDURE OnTaskComplete(toTask, tvResult)
        ? "Resultado: " + tvResult
    ENDPROC
    
    PROCEDURE OnTaskFailed(toTask, tcError)
        ? "Error: " + tcError
    ENDPROC
ENDDEFINE

Explicación:

  1. Creamos un array bidimensional y un objeto con propiedades.
  2. Pasamos estas estructuras complejas a la tarea con loTask.SetVariable().
  3. El array se pasa por referencia usando @ para mayor eficiencia.
  4. En la tarea, accedemos a las propiedades del objeto y a los elementos del array.
  5. Esto permite trabajar con estructuras de datos complejas en tareas paralelas.

Esta técnica es especialmente útil para procesar conjuntos de datos estructurados o configuraciones complejas.

Ejemplo 8: Obtener la primera tarea completada

Este ejemplo muestra cómo ejecutar varias tareas en paralelo y obtener el resultado de la primera que se complete.

* Cargar FoxCore
DO "ruta\a\FoxCore-VFP9-v1.0.app"

* Crear scripts que simulan búsquedas en diferentes fuentes
LOCAL ARRAY laScripts[3]
TEXT TO laScripts[1] NOSHOW
    * Búsqueda en la primera fuente (tarda 4 segundos)
    WAIT WINDOW "Buscando en la fuente 1..." TIMEOUT 4
    * Simulamos que no encontramos resultados
    RETURN .NULL.
ENDTEXT

TEXT TO laScripts[2] NOSHOW
    * Búsqueda en la segunda fuente (tarda 2 segundos)
    WAIT WINDOW "Buscando en la fuente 2..." TIMEOUT 2
    * Simulamos que encontramos resultados
    RETURN "Resultado encontrado en la fuente 2"
ENDTEXT

TEXT TO laScripts[3] NOSHOW
    * Búsqueda en la tercera fuente (tarda 3 segundos)
    WAIT WINDOW "Buscando en la fuente 3..." TIMEOUT 3
    * Simulamos que encontramos resultados
    RETURN "Resultado encontrado en la fuente 3"
ENDTEXT

* Ejecutar todas las búsquedas en paralelo
PUBLIC loTasks
loTasks = _screen.FoxCore.RunMultiple(@laScripts)

* Esperar a la primera tarea que se complete y tenga un resultado no nulo
LOCAL lnTaskIndex, lvResult
lvResult = .NULL.

DO WHILE lvResult == .NULL.
    * Esperar a que cualquier tarea se complete
    lnTaskIndex = _screen.FoxCore.WaitAny(@loTasks, 10)
    
    IF lnTaskIndex > 0
        * Verificar si la tarea completada tiene un resultado
        lvResult = loTasks[lnTaskIndex].GetResult()
        
        IF lvResult != .NULL.
            ? "¡Encontramos un resultado en la fuente " + TRANSFORM(lnTaskIndex) + "!"
            ? "Resultado: " + TRANSFORM(lvResult)
            
            * Cancelar las demás tareas ya que tenemos un resultado
            FOR i = 1 TO ALEN(loTasks)
                IF i != lnTaskIndex AND loTasks[i].GetStatus() = "running"
                    loTasks[i].Cancel("Ya tenemos un resultado, cancelando búsqueda")
                ENDIF
            NEXT
            
            EXIT
        ELSE
            ? "La fuente " + TRANSFORM(lnTaskIndex) + " no encontró resultados. Continuando búsqueda..."
        ENDIF
    ELSE
        * Timeout - ninguna tarea se completó en el tiempo especificado
        ? "Timeout esperando resultados. Abortando búsqueda."
        
        * Cancelar todas las tareas
        FOR i = 1 TO ALEN(loTasks)
            IF loTasks[i].GetStatus() = "running"
                loTasks[i].Cancel("Timeout general")
            ENDIF
        NEXT
        
        EXIT
    ENDIF
ENDDO

* Mostrar resumen final
? ""
? "=== RESUMEN DE BÚSQUEDA ==="
FOR i = 1 TO ALEN(loTasks)
    ? "Fuente " + TRANSFORM(i) + ": " + loTasks[i].GetStatus()
NEXT

IF lvResult != .NULL.
    ? "Resultado final: " + TRANSFORM(lvResult)
ELSE
    ? "No se encontraron resultados en ninguna fuente."
ENDIF

Explicación:

  1. Creamos tres tareas que simulan búsquedas en diferentes fuentes de datos.
  2. Ejecutamos todas las búsquedas en paralelo.
  3. Utilizamos _screen.FoxCore.WaitAny() para esperar a que cualquier tarea se complete.
  4. Cuando una tarea encuentra un resultado válido, cancelamos las demás tareas.
  5. Este patrón implementa el concepto de "carrera" donde solo nos interesa el primer resultado válido.

Esta técnica es muy útil para escenarios donde necesitas obtener información de múltiples fuentes pero solo necesitas un resultado válido.

Ejemplo 9: Eventos WhenAny

Este ejemplo muestra cómo utilizar eventos para responder cuando cualquier tarea se complete.

* Cargar FoxCore
DO "ruta\a\FoxCore-VFP9-v1.0.app"

* Crear varios scripts con diferentes tiempos de ejecución
LOCAL ARRAY laScripts[4]
TEXT TO laScripts[1] NOSHOW
    WAIT WINDOW "Tarea 1 ejecutándose..." TIMEOUT 3
    RETURN "Resultado de la tarea 1"
ENDTEXT

TEXT TO laScripts[2] NOSHOW
    WAIT WINDOW "Tarea 2 ejecutándose..." TIMEOUT 5
    RETURN "Resultado de la tarea 2"
ENDTEXT

TEXT TO laScripts[3] NOSHOW
    WAIT WINDOW "Tarea 3 ejecutándose..." TIMEOUT 2
    RETURN "Resultado de la tarea 3"
ENDTEXT

TEXT TO laScripts[4] NOSHOW
    WAIT WINDOW "Tarea 4 ejecutándose..." TIMEOUT 4
    RETURN "Resultado de la tarea 4"
ENDTEXT

* Crear el manejador de eventos
PUBLIC loHandler, loTasks
loHandler = CREATEOBJECT("WhenAnyHandler")

* Ejecutar todas las tareas en paralelo
loTasks = _screen.FoxCore.RunMultiple(@laScripts)

* Configurar evento WhenAny para responder cuando cualquier tarea se complete
_screen.FoxCore.WhenAny(@loTasks, loHandler, "OnAnyTaskComplete")

* Esperar a que todas las tareas terminen
_screen.FoxCore.WaitAll(loTasks, 60)

? "Todas las tareas han finalizado."

* Manejador de eventos para WhenAny
DEFINE CLASS WhenAnyHandler AS CUSTOM
    nCompletedCount = 0
    
    PROCEDURE OnAnyTaskComplete(toTask, tvResult)
        THIS.nCompletedCount = THIS.nCompletedCount + 1
        
        ? "¡Una tarea se ha completado! (" + TRANSFORM(THIS.nCompletedCount) + " de 4)"
        ? "ID de la tarea: " + toTask.GetTaskId()
        ? "Resultado: " + TRANSFORM(tvResult)
        ? "Tiempo de ejecución: " + TRANSFORM(toTask.GetExecutionTime()) + " segundos"
        ? ""
        
        * Podemos realizar acciones específicas según qué tarea se completó
        IF toTask.GetTaskId() = "Task_3"  && La tarea 3 es la más rápida
            ? "¡La tarea más rápida se ha completado!"
        ENDIF
    ENDPROC
ENDDEFINE

Explicación:

  1. Creamos cuatro tareas con diferentes tiempos de ejecución.
  2. Utilizamos _screen.FoxCore.WhenAny() para configurar un evento que se dispara cuando cualquier tarea se completa.
  3. El manejador de eventos recibe la tarea completada y su resultado.
  4. Podemos realizar acciones específicas basadas en qué tarea se completó.
  5. A diferencia de WaitAny, este enfoque basado en eventos no bloquea la ejecución.

Este patrón es útil cuando necesitas responder de forma asíncrona a la finalización de tareas sin bloquear el hilo principal.

Ejemplo 10: Eventos WhenAll

Este ejemplo muestra cómo utilizar eventos para responder cuando todas las tareas se completen.

* Cargar FoxCore
DO "ruta\a\FoxCore-VFP9-v1.0.app"

* Crear varios scripts para procesar diferentes partes de un informe
LOCAL ARRAY laScripts[3]
TEXT TO laScripts[1] NOSHOW
    * Procesar datos de ventas
    WAIT WINDOW "Procesando datos de ventas..." TIMEOUT 3
    RETURN "Datos de ventas procesados: 1500 registros"
ENDTEXT

TEXT TO laScripts[2] NOSHOW
    * Procesar datos de inventario
    WAIT WINDOW "Procesando datos de inventario..." TIMEOUT 4
    RETURN "Datos de inventario procesados: 2300 productos"
ENDTEXT

TEXT TO laScripts[3] NOSHOW
    * Procesar datos de clientes
    WAIT WINDOW "Procesando datos de clientes..." TIMEOUT 2
    RETURN "Datos de clientes procesados: 850 clientes"
ENDTEXT

* Crear el manejador de eventos
PUBLIC loHandler, loTasks
loHandler = CREATEOBJECT("WhenAllHandler")

* Ejecutar todas las tareas en paralelo
loTasks = _screen.FoxCore.RunMultiple(@laScripts)

* Configurar eventos para monitorear tareas individuales
_screen.FoxCore.AddEventListener("OnTaskComplete", loHandler, "OnTaskComplete")
_screen.FoxCore.AddEventListener("OnTaskFailed", loHandler, "OnTaskFailed")

* Configurar evento WhenAll para responder cuando todas las tareas se completen
_screen.FoxCore.WhenAll(@loTasks, loHandler, "OnAllTasksComplete")

* Esperar a que todas las tareas terminen (opcional, ya que estamos usando eventos)
_screen.FoxCore.WaitAll(loTasks, 60)

* Manejador de eventos para WhenAll
DEFINE CLASS WhenAllHandler AS CUSTOM
    nCompletedCount = 0
    nTotalTasks = 3
    DIMENSION aResults[3]
    
    PROCEDURE OnTaskComplete(toTask, tvResult)
        THIS.nCompletedCount = THIS.nCompletedCount + 1
        
        * Guardar el resultado
        LOCAL lnIndex
        lnIndex = VAL(SUBSTR(toTask.GetTaskId(), 6))  && Extraer el número de la tarea
        THIS.aResults[lnIndex] = tvResult
        
        ? "Tarea " + toTask.GetTaskId() + " completada (" + TRANSFORM(THIS.nCompletedCount) + " de " + TRANSFORM(THIS.nTotalTasks) + ")"
    ENDPROC
    
    PROCEDURE OnTaskFailed(toTask, tcError)
        ? "Error en la tarea " + toTask.GetTaskId() + ": " + tcError
    ENDPROC
    
    PROCEDURE OnAllTasksComplete(taResults)
        ? ""
        ? "=== TODAS LAS TAREAS COMPLETADAS ==="
        ? "Tiempo total de procesamiento: " + TRANSFORM(_screen.FoxCore.GetTotalExecutionTime()) + " segundos"
        
        * Generar informe final
        ? ""
        ? "=== INFORME FINAL ==="
        FOR i = 1 TO ALEN(THIS.aResults)
            ? THIS.aResults[i]
        NEXT
        
        * Realizar acciones finales
        ? ""
        ? "Generando informe consolidado..."
        ? "Informe completado y listo para su visualización."
    ENDPROC
ENDDEFINE

Explicación:

  1. Creamos tres tareas para procesar diferentes partes de un informe.
  2. Configuramos eventos para monitorear las tareas individuales.
  3. Utilizamos _screen.FoxCore.WhenAll() para configurar un evento que se dispara cuando todas las tareas se completan.
  4. En el evento OnAllTasksComplete, generamos un informe consolidado con los resultados de todas las tareas.
  5. Este enfoque basado en eventos permite responder de forma asíncrona a la finalización de todas las tareas.

Este patrón es útil para escenarios donde necesitas realizar un procesamiento final después de que todas las tareas paralelas hayan terminado.

Ejemplo 11: Tareas secuenciales

Este ejemplo muestra cómo ejecutar tareas en secuencia, donde cada tarea depende del resultado de la anterior.

* Cargar FoxCore
DO "ruta\a\FoxCore-VFP9-v1.0.app"

* Definir la primera tarea: obtener datos
TEXT TO lcScript1 NOSHOW
    * Simular obtención de datos
    WAIT WINDOW "Obteniendo datos..." TIMEOUT 2
    
    * Crear un cursor con datos de ejemplo
    CREATE CURSOR datos (id I, nombre C(30), valor N(10,2))
    INSERT INTO datos VALUES (1, 'Producto A', 150.50)
    INSERT INTO datos VALUES (2, 'Producto B', 75.25)
    INSERT INTO datos VALUES (3, 'Producto C', 200.00)
    
    * Retornar el nombre del cursor
    RETURN "datos"
ENDTEXT

* Crear y ejecutar la primera tarea
PUBLIC loTask1, loHandler
loHandler = CREATEOBJECT("SequentialTaskHandler")
loTask1 = _screen.FoxCore.NewTask(lcScript1)
loTask1.AddEventListener("OnComplete", loHandler, "OnTask1Complete")
loTask1.AddEventListener("OnFailed", loHandler, "OnTaskFailed")
loTask1.Run()

* Esperamos a que termine la primera tarea
loTask1.Wait(30)

* Manejador de eventos para tareas secuenciales
DEFINE CLASS SequentialTaskHandler AS CUSTOM
    PROCEDURE OnTask1Complete(toTask, tvResult)
        ? "Tarea 1 completada. Resultado: " + tvResult
        
        * Definir la segunda tarea que procesa los datos obtenidos
        LOCAL lcScript2
        TEXT TO lcScript2 NOSHOW
            * Abrir el cursor creado por la primera tarea
            SELECT datos
            
            * Procesar los datos
            LOCAL lnTotal
            lnTotal = 0
            
            SCAN
                lnTotal = lnTotal + valor
                WAIT WINDOW "Procesando " + ALLTRIM(nombre) + "..." TIMEOUT 1
            ENDSCAN
            
            * Retornar el total calculado
            RETURN lnTotal
        ENDTEXT
        
        * Crear y ejecutar la segunda tarea
        PUBLIC loTask2
        loTask2 = _screen.FoxCore.NewTask(lcScript2)
        loTask2.AddEventListener("OnComplete", THIS, "OnTask2Complete")
        loTask2.AddEventListener("OnFailed", THIS, "OnTaskFailed")
        loTask2.Run()
    ENDPROC
    
    PROCEDURE OnTask2Complete(toTask, tvResult)
        ? "Tarea 2 completada. Total calculado: " + TRANSFORM(tvResult)
        
        * Definir la tercera tarea que genera un informe
        LOCAL lcScript3
        TEXT TO lcScript3 NOSHOW
            * Generar informe
            LOCAL lcInforme, lcRuta
            
            lcInforme = "INFORME DE PRODUCTOS" + CHR(13) + CHR(10)
            lcInforme = lcInforme + "Fecha: " + DTOC(DATE()) + CHR(13) + CHR(10)
            lcInforme = lcInforme + "----------------------------------------" + CHR(13) + CHR(10)
            
            SELECT datos
            SCAN
                lcInforme = lcInforme + PADL(TRANSFORM(id), 5) + " " + ;
                             PADR(nombre, 30) + " " + ;
                             PADL(TRANSFORM(valor, "999,999.99"), 12) + CHR(13) + CHR(10)
            ENDSCAN
            
            lcInforme = lcInforme + "----------------------------------------" + CHR(13) + CHR(10)
            lcInforme = lcInforme + "Total: " + TRANSFORM(SUM(valor), "999,999.99") + CHR(13) + CHR(10)
            
            * Guardar el informe
            lcRuta = "C:\informes\informe_productos.txt"
            STRTOFILE(lcInforme, lcRuta)
            
            RETURN lcRuta
        ENDTEXT
        
        * Crear y ejecutar la tercera tarea
         PUBLIC loTask3
        loTask3 = _screen.FoxCore.NewTask(lcScript3)
        loTask3.AddEventListener("OnComplete", THIS, "OnTask3Complete")
        loTask3.AddEventListener("OnFailed", THIS, "OnTaskFailed")
        loTask3.Run()
    ENDPROC
    
    PROCEDURE OnTask3Complete(toTask, tvResult)
        ? "Tarea 3 completada. Informe generado en: " + tvResult
        ? "Proceso completo finalizado con éxito."
    ENDPROC
    
    PROCEDURE OnTaskFailed(toTask, tcError)
        ? "Error en la tarea " + toTask.GetTaskId() + ": " + tcError
        ? "Proceso secuencial interrumpido."
    ENDPROC
ENDDEFINE

Explicación:

  1. Creamos tres tareas que se ejecutan en secuencia, donde cada una depende del resultado de la anterior.
  2. La primera tarea obtiene datos y crea un cursor.
  3. La segunda tarea procesa los datos del cursor y calcula un total.
  4. La tercera tarea genera un informe con los datos procesados.
  5. Utilizamos eventos para iniciar cada tarea después de que la anterior se complete.

Este patrón es útil para flujos de trabajo donde cada paso depende del resultado del paso anterior, pero aún queremos aprovechar la ejecución asíncrona.

Ejemplo 12: Tarea simple

Este ejemplo muestra cómo ejecutar una tarea simple y obtener su resultado de manera síncrona.

* Cargar FoxCore
DO "ruta\a\FoxCore-VFP9-v1.0.app"

* Definir una tarea simple
TEXT TO lcScript NOSHOW
    * Realizar un cálculo intensivo
    LOCAL i, j, lnResultado
    lnResultado = 0
    
    FOR i = 1 TO 1000
        FOR j = 1 TO 1000
            lnResultado = lnResultado + (i * j / 1000)
        ENDFOR
    ENDFOR
    
    RETURN lnResultado
ENDTEXT

* Medir el tiempo de ejecución
LOCAL lnInicio, lnFin, lnTiempo
lnInicio = SECONDS()

* Crear y ejecutar la tarea
PUBLIC loTask
loTask = _screen.FoxCore.NewTask(lcScript)
loTask.Run()

* Esperar a que termine y obtener el resultado
IF loTask.Wait(30)
    lnFin = SECONDS()
    lnTiempo = lnFin - lnInicio
    
    ? "Tarea completada en " + TRANSFORM(lnTiempo) + " segundos"
    ? "Resultado: " + TRANSFORM(loTask.GetResult())
ELSE
    ? "La tarea no se completó en el tiempo especificado"
ENDIF

* Verificar el estado y tiempo de ejecución
? "Estado: " + loTask.GetStatus()
? "Tiempo de ejecución: " + TRANSFORM(loTask.GetExecutionTime()) + " segundos"

Explicación:

  1. Definimos una tarea que realiza un cálculo intensivo.
  2. Medimos el tiempo de ejecución total.
  3. Ejecutamos la tarea y esperamos de forma síncrona a que termine con loTask.Wait(30).
  4. Obtenemos el resultado con loTask.GetResult().
  5. Verificamos el estado y tiempo de ejecución de la tarea.

Este patrón es útil para tareas simples donde queremos aprovechar la ejecución en segundo plano pero necesitamos esperar el resultado antes de continuar.

Ejemplo 13: Estadísticas de ejecución

Este ejemplo muestra cómo obtener estadísticas detalladas sobre la ejecución de tareas.

* Cargar FoxCore
DO "ruta\a\FoxCore-VFP9-v1.0.app"

* Crear varios scripts con diferentes cargas de trabajo
LOCAL ARRAY laScripts[5]
TEXT TO laScripts[1] NOSHOW
    * Tarea CPU intensiva
    LOCAL i, j, lnResultado
    lnResultado = 0
    FOR i = 1 TO 1000
        FOR j = 1 TO 1000
            lnResultado = lnResultado + (i * j / 1000)
        ENDFOR
    ENDFOR
    RETURN "Tarea CPU completada"
ENDTEXT

TEXT TO laScripts[2] NOSHOW
    * Tarea de espera
    WAIT WINDOW "Esperando..." TIMEOUT 3
    RETURN "Tarea de espera completada"
ENDTEXT

TEXT TO laScripts[3] NOSHOW
    * Tarea de memoria
    LOCAL ARRAY laData[10000, 10]
    LOCAL i, j
    FOR i = 1 TO 10000
        FOR j = 1 TO 10
            laData[i, j] = i * j
        ENDFOR
    ENDFOR
    RETURN "Tarea de memoria completada"
ENDTEXT

TEXT TO laScripts[4] NOSHOW
    * Tarea de archivos
    LOCAL i, lcArchivo, lcContenido
    lcContenido = REPLICATE("X", 1000000)  && 1MB de datos
    FOR i = 1 TO 5
        lcArchivo = "C:\temp\archivo" + TRANSFORM(i) + ".dat"
        STRTOFILE(lcContenido, lcArchivo)
        ERASE (lcArchivo)
    ENDFOR
    RETURN "Tarea de archivos completada"
ENDTEXT

TEXT TO laScripts[5] NOSHOW
    * Tarea con error
    LOCAL x
    x = 1 / 0  && División por cero
    RETURN "Esta línea nunca se ejecutará"
ENDTEXT

* Crear el manejador de estadísticas
PUBLIC loHandler, loTasks
loHandler = CREATEOBJECT("StatsHandler")

* Ejecutar todas las tareas en paralelo
loTasks = _screen.FoxCore.RunMultiple(@laScripts)

* Vincular eventos para recopilar estadísticas
_screen.FoxCore.AddEventListener("OnTaskComplete", loHandler, "OnTaskComplete")
_screen.FoxCore.AddEventListener("OnTaskFailed", loHandler, "OnTaskFailed")

* Esperar a que todas las tareas terminen
_screen.FoxCore.WaitAll(loTasks, 60)

* Mostrar estadísticas finales
loHandler.ShowStats()

* Manejador de estadísticas
DEFINE CLASS StatsHandler AS CUSTOM
    DIMENSION aTaskStats[5, 3]  && [Tarea, Estado, Tiempo]
    
    PROCEDURE INIT
        * Inicializar estadísticas
        FOR i = 1 TO 5
            THIS.aTaskStats[i, 1] = "Tarea " + TRANSFORM(i)
            THIS.aTaskStats[i, 2] = "Pendiente"
            THIS.aTaskStats[i, 3] = 0
        ENDFOR
    ENDPROC
    
    PROCEDURE OnTaskComplete(toTask, tvResult)
        LOCAL lnTaskNum
        lnTaskNum = VAL(SUBSTR(toTask.GetTaskId(), 6))
        
        THIS.aTaskStats[lnTaskNum, 2] = "Completada"
        THIS.aTaskStats[lnTaskNum, 3] = toTask.GetExecutionTime()
    ENDPROC
    
    PROCEDURE OnTaskFailed(toTask, tcError)
        LOCAL lnTaskNum
        lnTaskNum = VAL(SUBSTR(toTask.GetTaskId(), 6))
        
        THIS.aTaskStats[lnTaskNum, 2] = "Error: " + tcError
        THIS.aTaskStats[lnTaskNum, 3] = toTask.GetExecutionTime()
    ENDPROC
    
    PROCEDURE ShowStats
        CLEAR
        ? "=== ESTADÍSTICAS DE EJECUCIÓN ==="
        ? "Tiempo total: " + TRANSFORM(_screen.FoxCore.GetTotalExecutionTime()) + " segundos"
        ? ""
        ? "Tarea                Estado                  Tiempo (s)"
        ? "----------------------------------------------------------------"
        
        LOCAL lcTarea, lcEstado, lnTiempo
        FOR i = 1 TO 5
            lcTarea = PADR(THIS.aTaskStats[i, 1], 20)
            lcEstado = PADR(THIS.aTaskStats[i, 2], 25)
            lnTiempo = THIS.aTaskStats[i, 3]
            
            ? lcTarea + lcEstado + TRANSFORM(lnTiempo, "999.999")
        NEXT
        
        ? "----------------------------------------------------------------"
        
        * Obtener estadísticas del sistema
        LOCAL loStats
        loStats = _screen.FoxCore.GetSystemStats()
        ? ""
        ? "=== ESTADÍSTICAS DEL SISTEMA ==="
        ? "Procesadores lógicos: " + TRANSFORM(loStats.LogicalProcessors)
        ? "Memoria disponible: " + TRANSFORM(loStats.AvailableMemory) + " GB"
    ENDPROC
ENDDEFINE

Explicación:

  1. Creamos cinco tareas con diferentes tipos de carga: CPU, espera, memoria, archivos y una con error.
  2. Implementamos un manejador que recopila estadísticas sobre cada tarea.
  3. Ejecutamos todas las tareas en paralelo y esperamos a que terminen.
  4. Mostramos estadísticas detalladas sobre el tiempo de ejecución y estado de cada tarea.
  5. También mostramos estadísticas del sistema como procesadores lógicos y memoria disponible.

Este patrón es útil para analizar el rendimiento de diferentes tipos de tareas y optimizar la ejecución paralela.

Ejemplo 14: Eventos WhenAll con estadísticas

Este ejemplo muestra cómo utilizar eventos WhenAll para generar estadísticas detalladas después de que todas las tareas se completen.

* Cargar FoxCore
DO "ruta\a\FoxCore-VFP9-v1.0.app"

* Crear scripts para procesar diferentes archivos
LOCAL ARRAY laScripts[5], laArchivos[5]
laArchivos[1] = "C:\datos\archivo1.dbf"
laArchivos[2] = "C:\datos\archivo2.dbf"
laArchivos[3] = "C:\datos\archivo3.dbf"
laArchivos[4] = "C:\datos\archivo4.dbf"
laArchivos[5] = "C:\datos\archivo5.dbf"

* Generar scripts para procesar cada archivo
FOR i = 1 TO 5
    TEXT TO laScripts[i] TEXTMERGE NOSHOW
        * Procesar archivo <>
        LOCAL lnRegistros, lnTiempo
        lnTiempo = SECONDS()
        
        * Simular procesamiento
        WAIT WINDOW "Procesando <>..." TIMEOUT <>
        
        * Simular resultados
        lnRegistros = <>
        
        * Crear objeto de resultado
        LOCAL loResult
        loResult = CREATEOBJECT("Empty")
        loResult.Archivo = "<>"
        loResult.Registros = lnRegistros
        loResult.Tiempo = SECONDS() - lnTiempo
        
        RETURN loResult
    ENDTEXT
ENDFOR

* Crear el manejador de estadísticas
PUBLIC loHandler, loTasks
loHandler = CREATEOBJECT("StatsHandler")

* Ejecutar todas las tareas en paralelo
loTasks = _screen.FoxCore.RunMultiple(@laScripts)

* Configurar evento WhenAll para generar estadísticas
_screen.FoxCore.WhenAll(@loTasks, loHandler, "OnAllTasksComplete")

* Esperar a que todas las tareas terminen
_screen.FoxCore.WaitAll(loTasks, 60)

* Manejador de estadísticas
DEFINE CLASS StatsHandler AS CUSTOM
    DIMENSION aResults[5]
    
    PROCEDURE OnAllTasksComplete(taResults)
        * Guardar resultados
        THIS.aResults = taResults
        
        * Generar informe de estadísticas
        THIS.GenerateStats()
    ENDPROC
    
    PROCEDURE GenerateStats
        CLEAR
        ? "=== INFORME DE PROCESAMIENTO ==="
        ? "Fecha: " + DTOC(DATE()) + " " + TIME()
        ? "Tiempo total: " + TRANSFORM(_screen.FoxCore.GetTotalExecutionTime()) + " segundos"
        ? ""
        ? "Archivo                          Registros    Tiempo (s)   Reg/seg"
        ? "---------------------------------------------------------------------"
        
        LOCAL lcArchivo, lnRegistros, lnTiempo, lnRegPorSeg
        LOCAL lnTotalRegistros, lnTiempoTotal, lnRegPorSegTotal
        
        lnTotalRegistros = 0
        lnTiempoTotal = 0
        
        FOR i = 1 TO ALEN(THIS.aResults)
            lcArchivo = PADR(THIS.aResults[i].Archivo, 30)
            lnRegistros = THIS.aResults[i].Registros
            lnTiempo = THIS.aResults[i].Tiempo
            lnRegPorSeg = IIF(lnTiempo > 0, lnRegistros / lnTiempo, 0)
            
            ? lcArchivo + TRANSFORM(lnRegistros, "999,999") + "    " + ;
              TRANSFORM(lnTiempo, "999.999") + "    " + ;
              TRANSFORM(lnRegPorSeg, "999,999.99")
              
            lnTotalRegistros = lnTotalRegistros + lnRegistros
            lnTiempoTotal = lnTiempoTotal + lnTiempo
        ENDFOR
        
        lnRegPorSegTotal = IIF(lnTiempoTotal > 0, lnTotalRegistros / lnTiempoTotal, 0)
        
        ? "---------------------------------------------------------------------"
        ? "TOTAL                          " + TRANSFORM(lnTotalRegistros, "999,999") + "    " + ;
          TRANSFORM(lnTiempoTotal, "999.999") + "    " + ;
          TRANSFORM(lnRegPorSegTotal, "999,999.99")
          
        * Generar gráfico de rendimiento (simulado)
        ? ""
        ? "=== GRÁFICO DE RENDIMIENTO ==="
        FOR i = 1 TO ALEN(THIS.aResults)
            lnRegPorSeg = IIF(THIS.aResults[i].Tiempo > 0, THIS.aResults[i].Registros / THIS.aResults[i].Tiempo, 0)
            lcBarra = REPLICATE("█", INT(lnRegPorSeg / 1000))
            
            ? "Archivo " + TRANSFORM(i) + ": " + lcBarra + " " + TRANSFORM(lnRegPorSeg, "999,999.99") + " reg/seg"
        ENDFOR
    ENDPROC
ENDDEFINE

Explicación:

  1. Creamos cinco tareas para procesar diferentes archivos.
  2. Cada tarea devuelve un objeto con información sobre el procesamiento.
  3. Utilizamos _screen.FoxCore.WhenAll() para generar estadísticas cuando todas las tareas se completen.
  4. En el método GenerateStats(), creamos un informe detallado con estadísticas de rendimiento.
  5. Incluimos un gráfico de barras simple para visualizar el rendimiento relativo de cada tarea.

Este patrón es útil para analizar y comparar el rendimiento de diferentes tareas, y generar informes detallados de procesamiento.

Ejemplo 15: Tareas secuenciales con resultados previos

Este ejemplo muestra cómo ejecutar tareas en secuencia, pasando el resultado de cada tarea a la siguiente.

* Cargar FoxCore
DO "ruta\a\FoxCore-VFP9-v1.0.app"

* Definir la primera tarea: generar datos aleatorios
TEXT TO lcScript1 NOSHOW
    * Generar datos aleatorios
    LOCAL ARRAY laNumeros[1000]
    LOCAL i
    
    FOR i = 1 TO 1000
        laNumeros[i] = INT(RAND() * 1000)
    ENDFOR
    
    RETURN @laNumeros
ENDTEXT

* Crear y ejecutar la primera tarea
PUBLIC loTask1, loHandler
loHandler = CREATEOBJECT("SequentialTaskHandler")
loTask1 = _screen.FoxCore.NewTask(lcScript1)
loTask1.AddEventListener("OnComplete", loHandler, "OnTask1Complete")
loTask1.AddEventListener("OnFailed", loHandler, "OnTaskFailed")
loTask1.Run()

* Esperar a que termine la primera tarea
loTask1.Wait(30)

* Manejador de eventos para tareas secuenciales
DEFINE CLASS SequentialTaskHandler AS CUSTOM
    PROCEDURE OnTask1Complete(toTask, tvResult)
        ? "Tarea 1 completada. Generados " + TRANSFORM(ALEN(tvResult)) + " números aleatorios."
        
        * Definir la segunda tarea: ordenar los números
        LOCAL lcScript2
        TEXT TO lcScript2 NOSHOW
            * Ordenar el array recibido
            LOCAL ARRAY laNumeros[1]
            laNumeros = laInput  && laInput contiene el array pasado desde la tarea anterior
            
            * Algoritmo de ordenación simple (burbuja)
            LOCAL i, j, lnTemp, lnLen
            lnLen = ALEN(laNumeros)
            
            FOR i = 1 TO lnLen - 1
                FOR j = 1 TO lnLen - i
                    IF laNumeros[j] > laNumeros[j + 1]
                        lnTemp = laNumeros[j]
                        laNumeros[j] = laNumeros[j + 1]
                        laNumeros[j + 1] = lnTemp
                    ENDIF
                ENDFOR
                
                * Mostrar progreso cada 100 iteraciones
                IF i % 100 = 0
                    WAIT WINDOW "Ordenando... " + TRANSFORM(i / (lnLen - 1) * 100, "999.9") + "%" NOWAIT
                ENDIF
            ENDFOR
            
            RETURN @laNumeros
        ENDTEXT
        
        * Crear y ejecutar la segunda tarea
        PUBLIC loTask2
        loTask2 = _screen.FoxCore.NewTask(lcScript2)
        
        * Pasar el resultado de la primera tarea a la segunda
        loTask2.SetVariable("laInput", tvResult)
        
        loTask2.AddEventListener("OnComplete", THIS, "OnTask2Complete")
        loTask2.AddEventListener("OnFailed", THIS, "OnTaskFailed")
        loTask2.Run()
    ENDPROC
    
    PROCEDURE OnTask2Complete(toTask, tvResult)
        ? "Tarea 2 completada. Array ordenado."
        
        * Definir la tercera tarea: calcular estadísticas
        LOCAL lcScript3
        TEXT TO lcScript3 NOSHOW
            * Calcular estadísticas del array ordenado
            LOCAL ARRAY laNumeros[1]
            laNumeros = laInput  && laInput contiene el array ordenado
            
            LOCAL lnLen, lnMin, lnMax, lnSum, lnAvg, lnMedian
            lnLen = ALEN(laNumeros)
            lnMin = laNumeros[1]
            lnMax = laNumeros[lnLen]
            lnSum = 0
            
            * Calcular suma
            LOCAL i
            FOR i = 1 TO lnLen
                lnSum = lnSum + laNumeros[i]
            ENDFOR
            
            * Calcular promedio
            lnAvg = lnSum / lnLen
            
            * Calcular mediana
            IF MOD(lnLen, 2) = 0
                lnMedian = (laNumeros[lnLen/2] + laNumeros[lnLen/2 + 1]) / 2
            ELSE
                lnMedian = laNumeros[INT(lnLen/2) + 1]
            ENDIF
            
            * Crear objeto de resultado
            LOCAL loStats
            loStats = CREATEOBJECT("Empty")
            loStats.Count = lnLen
            loStats.Min = lnMin
            loStats.Max = lnMax
            loStats.Sum = lnSum
            loStats.Average = lnAvg
            loStats.Median = lnMedian
            
            RETURN loStats
        ENDTEXT
        
        * Crear y ejecutar la tercera tarea
        PUBLIC loTask3
        loTask3 = _screen.FoxCore.NewTask(lcScript3)
        
        * Pasar el resultado de la segunda tarea a la tercera
        loTask3.SetVariable("laInput", tvResult)
        
        loTask3.AddEventListener("OnComplete", THIS, "OnTask3Complete")
        loTask3.AddEventListener("OnFailed", THIS, "OnTaskFailed")
        loTask3.Run()
    ENDPROC
    
    PROCEDURE OnTask3Complete(toTask, tvResult)
        ? "Tarea 3 completada. Estadísticas calculadas."
        ? ""
        ? "=== ESTADÍSTICAS DE LOS NÚMEROS ==="
        ? "Cantidad: " + TRANSFORM(tvResult.Count)
        ? "Mínimo: " + TRANSFORM(tvResult.Min)
        ? "Máximo: " + TRANSFORM(tvResult.Max)
        ? "Suma: " + TRANSFORM(tvResult.Sum)
        ? "Promedio: " + TRANSFORM(tvResult.Average, "999.99")
        ? "Mediana: " + TRANSFORM(tvResult.Median, "999.99")
        ? ""
        ? "Proceso secuencial completado con éxito."
    ENDPROC
    
    PROCEDURE OnTaskFailed(toTask, tcError)
        ? "Error en la tarea " + toTask.GetTaskId() + ": " + tcError
        ? "Proceso secuencial interrumpido."
    ENDPROC
ENDDEFINE

Explicación:

  1. Creamos tres tareas que se ejecutan en secuencia, pasando datos entre ellas.
  2. La primera tarea genera números aleatorios.
  3. La segunda tarea recibe el array de números y los ordena.
  4. La tercera tarea recibe el array ordenado y calcula estadísticas.
  5. Utilizamos loTask.SetVariable() para pasar los resultados de una tarea a la siguiente.

Este patrón es útil para flujos de trabajo complejos donde cada paso procesa los datos generados por el paso anterior.

Ejemplo 16: Reportar progreso de tareas

Este ejemplo muestra cómo reportar y monitorear el progreso de tareas de larga duración.

* Cargar FoxCore
DO "ruta\a\FoxCore-VFP9-v1.0.app"

* Definir una tarea de larga duración que reporta progreso
TEXT TO lcScript NOSHOW
    * Tarea que procesa un gran volumen de datos
    LOCAL i, lnTotal, lnProgreso
    lnTotal = 1000
    
    FOR i = 1 TO lnTotal
        * Simular procesamiento
        INKEY(0.01)
        
        * Calcular y reportar progreso cada 10 iteraciones
        IF MOD(i, 10) = 0
            lnProgreso = i / lnTotal * 100
            
            * Reportar progreso usando la función especial ReportProgress
            ReportProgress(lnProgreso, "Procesando item " + TRANSFORM(i) + " de " + TRANSFORM(lnTotal))
        ENDIF
    ENDFOR
    
    RETURN "Procesamiento completado"
ENDTEXT

* Crear la tarea
PUBLIC loTask, loHandler
loHandler = CREATEOBJECT("ProgressHandler")
loTask = _screen.FoxCore.NewTask(lcScript)

* Vincular eventos
loTask.AddEventListener("OnComplete", loHandler, "OnTaskComplete")
loTask.AddEventListener("OnFailed", loHandler, "OnTaskFailed")
loTask.AddEventListener("OnProgress", loHandler, "OnTaskProgress")

* Ejecutar la tarea
loTask.Run()

* Esperar a que termine la tarea
loTask.Wait(60)

* Manejador de eventos con soporte para progreso
DEFINE CLASS ProgressHandler AS CUSTOM
    PROCEDURE OnTaskComplete(toTask, tvResult)
        ? ""
        ? "Tarea completada: " + tvResult
        ? "Tiempo total: " + TRANSFORM(toTask.GetExecutionTime()) + " segundos"
    ENDPROC
    
    PROCEDURE OnTaskFailed(toTask, tcError)
        ? ""
        ? "Error en la tarea: " + tcError
    ENDPROC
    
    PROCEDURE OnTaskProgress(toTask, tnPorcentaje, tcMensaje)
        * Actualizar la barra de progreso
        LOCAL lcBarra, lnLongitud, i
        lnLongitud = 50  && Longitud de la barra
        lcBarra = "["
        
        FOR i = 1 TO lnLongitud
            IF i <= (tnPorcentaje / 100 * lnLongitud)
                lcBarra = lcBarra + "█"
            ELSE
                lcBarra = lcBarra + " "
            ENDIF
        ENDFOR
        
        lcBarra = lcBarra + "] " + TRANSFORM(tnPorcentaje, "999.9") + "%"
        
        * Mostrar barra de progreso y mensaje
        CLEAR
        ? lcBarra
        ? tcMensaje
        ? "Tiempo transcurrido: " + TRANSFORM(toTask.GetExecutionTime()) + " segundos"
    ENDPROC
ENDDEFINE

Explicación:

  1. Creamos una tarea de larga duración que reporta su progreso periódicamente.
  2. Utilizamos la función especial ReportProgress() dentro de la tarea para informar del progreso.
  3. Implementamos un manejador de eventos con un método OnTaskProgress que muestra una barra de progreso visual.
  4. La barra de progreso se actualiza en tiempo real a medida que avanza la tarea.
  5. También mostramos el tiempo transcurrido para dar una idea del tiempo restante.

Este patrón es esencial para tareas de larga duración, ya que proporciona retroalimentación visual al usuario y permite estimar el tiempo restante.

Conclusión

Estos ejemplos muestran las diversas formas en que puedes utilizar FoxCore para implementar procesamiento paralelo y multitarea en tus aplicaciones Visual FoxPro. Desde tareas simples hasta flujos de trabajo complejos, FoxCore proporciona las herramientas necesarias para aprovechar al máximo los recursos del sistema y mejorar el rendimiento de tus aplicaciones.

Recuerda que puedes combinar estos patrones para crear soluciones personalizadas que se adapten a tus necesidades específicas. La clave está en identificar qué partes de tu aplicación pueden beneficiarse del procesamiento paralelo y aplicar el patrón más adecuado para cada caso.

Próximos pasos

  • Revisa la Referencia API para conocer todos los métodos y propiedades disponibles en FoxCore.
  • Visita el Catálogo de Herramientas para descubrir otras utilidades que pueden complementar FoxCore.