jueves, 15 de septiembre de 2011

Corutinas en Lua

Hoy escribiré acerca de las corutinas de Lua (coroutines en inglés). Sé que la documentación de lua, manuales, etc. no logran explicar bien qué son ni cómo funcionan (y los ejemplos vaya que son difíciles de entender) así que trataré de facilitarlo para todos.

Las corutinas son nuevos procesos (threads) que se ejecutan independientemente de otros procesos. No se pueden ejecutar en paralelo, pero si en forma secuencial.

Muchos dirán: "De que sirven las corutinas si podemos simplemente ejecutar X función". Bueno, la corutinas son más rápidas en ejecución que una función porque ademas de estar cargadas en la memoria tambien se ejecutan en procesos independientes. Es decir, al ejecutar una función simplemente corremos una serie de instrucciones cargadas en X dirección de la memoria (pero sigue siendo el mismo proceso), y al ejecutar una corutina se ejecuta un proceso alterno que ya tiene cargadas la serie de instrucciones a seguir siendo más rápida la respuesta.

Pero no solo esto, sino también dichas corutinas (en procesos distintos) pueden pausarse, resumirse, etc.

En resumen, la ventajas son:

- La ejecución más rapida de funciones
- Poder controlar el flujo de otras corutinas desde dentro, o fuera, de otras.

Pero bueno, para dejarlo más claro escribiré un ejemplo muy básico de cómo crear una corutina:

function Print(valor1, valor2)
  while true do
    valor1, valor2 = coroutine.yield(valor1, valor2);
  end
end

PrintEx = coroutine.wrap(Print, a, b);
print(PrintEx("Hola", "mundo!"));
print(PrintEx("Cómo", "estas?"));

Con éste código creamos una corutina infinita (nunca se terminará) llamada "PrintEx" basada en la función "Print" que cada vez que la llamemos imprimirá los argumentos que le enviemos (bien podríamos simplemente usar la función print("Hola", "Mundo"); pero el caso es explicar las corutinas).

Bueno, ahora paso por paso.

1.- La función que será nuestra corutina es la función "Print" y recibe 2 argumentos.

2.- Dicha función inicia un loop infinito dónde por cada vuelta pausará la corutina usando "coroutine.yield()";

3.- La función "coroutine.yield(valor1, valor2);" lo que hace es retornar los argumentos suministrados por la función. Algo así como el clásico "return valor1, valor2;" en la funciones normales.

4.- Noten la línea de código "valor1, valor2 = coroutine.yield(valor1, valor2)". Como ya sabemos, la función "coroutine.yield();" retornará al invocante los argumentos que pongamos dentro del paréntesis. Pero si anteponemos "variable1, variable2 = " a dicha función entonces le estamos indicando a la corutina que la próxima vez que sea invocada los argumentos suministrados por el nuevo invocador serán guardados en las variables que antepongamos a "coroutine.yield()". De otro modo cada que la corutina seá invocada sólo retornaría los valores suministrados la primera vez que se le invocó.

5.- Usé como generador de corutina la función "coroutine.wrap()" (porque es más adecuado para este ejemplo), la cual retornará una nueva función que cada vez que sea invocada resumirá o ejecutará la corutina. En otras palabras, es lo mismo que usar "coroutine.resume(corutina, argumentos)" sólo que no retorna el primer valor boleano, sino sólo los argumentos que retorna la corutina.

Espero no sea tan complicada esta explicación, y más adelante escribiré otro ejemplo pero ahora si usando la función generadora "coroutine.create()".

2 comentarios:

  1. Me gustaría que hicieras unos ejemplos webultra, no me quedo del todo claro lo de las co-rutinas.

    Disculpa si te molesto jajaja

    ResponderEliminar
    Respuestas
    1. Apenas ando suscribiendo mi celular a mi gmail por lo que no había visto tus comentarios. Hace tiempo que no programo en lua (unos meses) pero si te puedo hacer ejemplos de corutinas. Dame oportunidad y creo que este fin de semana podría publicar algo.

      Eliminar