Ejemplos de FoxCore
Contenido
- Ejemplo 1: Tarea básica con eventos
- Ejemplo 2: Múltiples tareas en paralelo
- Ejemplo 3: Procesamiento paralelo de registros
- Ejemplo 4: Estadísticas del sistema
- Ejemplo 5: Esperar cualquier tarea (WaitAny)
- Ejemplo 6: Pasar variables a una tarea
- Ejemplo 7: Pasar variables complejas
- Ejemplo 8: Obtener la primera tarea completada
- Ejemplo 9: Eventos WhenAny
- Ejemplo 10: Eventos WhenAll
- Ejemplo 11: Tareas secuenciales
- Ejemplo 12: Tarea simple
- Ejemplo 13: Estadísticas de ejecución
- Ejemplo 14: Eventos WhenAll con estadísticas
- Ejemplo 15: Tareas secuenciales con resultados previos
- Ejemplo 16: Reportar progreso de tareas
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:
- Cargamos FoxCore con
DO "ruta\a\FoxCore-VFP9-v1.0.app"
. - Establecemos un timeout de 50 segundos para las tareas.
- Definimos un script que muestra ventanas de espera y retorna un mensaje.
- Creamos una nueva tarea con
_screen.FoxCore.NewTask(lcScript)
. - Creamos un manejador de eventos y lo vinculamos a los eventos de la tarea.
- Ejecutamos la tarea con
loTask.Run()
. - 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:
- Definimos tres scripts diferentes para ejecutar en paralelo.
- Creamos un manejador de eventos que lleva un contador de tareas completadas.
- Ejecutamos todas las tareas en paralelo con
_screen.FoxCore.RunMultiple(@laScripts)
. - Vinculamos eventos a nivel global para todas las tareas.
- Esperamos a que todas las tareas terminen con
_screen.FoxCore.WaitAll(loTasks, 60)
. - 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:
- Abrimos una tabla y contamos el número total de registros.
- Dividimos los registros en lotes basados en el número de tareas paralelas.
- Creamos un script para cada lote que procesará un rango específico de registros.
- Ejecutamos todas las tareas en paralelo.
- Monitoreamos el progreso a través de eventos y mostramos estadísticas.
- 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:
- Obtenemos estadísticas del sistema con
_screen.FoxCore.GetSystemStats()
. - Creamos y ejecutamos múltiples tareas en paralelo.
- Implementamos un bucle de monitoreo que muestra estadísticas actualizadas cada 2 segundos.
- Utilizamos
_screen.FoxCore.GetTasksSummary()
para obtener información sobre el estado de todas las tareas. - 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:
- Creamos tres tareas con diferentes tiempos de ejecución.
- Ejecutamos todas las tareas en paralelo.
- Utilizamos
_screen.FoxCore.WaitAny(@loTasks, 10)
para esperar a que cualquier tarea se complete. - Procesamos cada resultado inmediatamente después de que una tarea se complete.
- 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:
- Definimos variables locales que queremos pasar a la tarea.
- Creamos un script que utiliza estas variables para crear archivos.
- Utilizamos
loTask.SetVariable()
para pasar cada variable a la tarea. - Las variables estarán disponibles en el contexto de ejecución de la tarea.
- 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:
- Creamos un array bidimensional y un objeto con propiedades.
- Pasamos estas estructuras complejas a la tarea con
loTask.SetVariable()
. - El array se pasa por referencia usando
@
para mayor eficiencia. - En la tarea, accedemos a las propiedades del objeto y a los elementos del array.
- 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:
- Creamos tres tareas que simulan búsquedas en diferentes fuentes de datos.
- Ejecutamos todas las búsquedas en paralelo.
- Utilizamos
_screen.FoxCore.WaitAny()
para esperar a que cualquier tarea se complete. - Cuando una tarea encuentra un resultado válido, cancelamos las demás tareas.
- 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:
- Creamos cuatro tareas con diferentes tiempos de ejecución.
- Utilizamos
_screen.FoxCore.WhenAny()
para configurar un evento que se dispara cuando cualquier tarea se completa. - El manejador de eventos recibe la tarea completada y su resultado.
- Podemos realizar acciones específicas basadas en qué tarea se completó.
- 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:
- Creamos tres tareas para procesar diferentes partes de un informe.
- Configuramos eventos para monitorear las tareas individuales.
- Utilizamos
_screen.FoxCore.WhenAll()
para configurar un evento que se dispara cuando todas las tareas se completan. - En el evento
OnAllTasksComplete
, generamos un informe consolidado con los resultados de todas las tareas. - 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:
- Creamos tres tareas que se ejecutan en secuencia, donde cada una depende del resultado de la anterior.
- La primera tarea obtiene datos y crea un cursor.
- La segunda tarea procesa los datos del cursor y calcula un total.
- La tercera tarea genera un informe con los datos procesados.
- 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:
- Definimos una tarea que realiza un cálculo intensivo.
- Medimos el tiempo de ejecución total.
- Ejecutamos la tarea y esperamos de forma síncrona a que termine con
loTask.Wait(30)
. - Obtenemos el resultado con
loTask.GetResult()
. - 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:
- Creamos cinco tareas con diferentes tipos de carga: CPU, espera, memoria, archivos y una con error.
- Implementamos un manejador que recopila estadísticas sobre cada tarea.
- Ejecutamos todas las tareas en paralelo y esperamos a que terminen.
- Mostramos estadísticas detalladas sobre el tiempo de ejecución y estado de cada tarea.
- 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:
- Creamos cinco tareas para procesar diferentes archivos.
- Cada tarea devuelve un objeto con información sobre el procesamiento.
- Utilizamos
_screen.FoxCore.WhenAll()
para generar estadísticas cuando todas las tareas se completen. - En el método
GenerateStats()
, creamos un informe detallado con estadísticas de rendimiento. - 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:
- Creamos tres tareas que se ejecutan en secuencia, pasando datos entre ellas.
- La primera tarea genera números aleatorios.
- La segunda tarea recibe el array de números y los ordena.
- La tercera tarea recibe el array ordenado y calcula estadísticas.
- 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:
- Creamos una tarea de larga duración que reporta su progreso periódicamente.
- Utilizamos la función especial
ReportProgress()
dentro de la tarea para informar del progreso. - Implementamos un manejador de eventos con un método
OnTaskProgress
que muestra una barra de progreso visual. - La barra de progreso se actualiza en tiempo real a medida que avanza la tarea.
- 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.