viernes, 29 de abril de 2011

Una posible respuesta al debate de multitarea [video]

Este es un artículo que salió el día 15 de este mes y lo teníamos pendiente. Trata el asunto de los diferentes enfoques de la multitarea sobre todo en dispositivos portátiles (las restricciones para los equipos de escritorio no son significativas). El original refiere un vídeo al principio que decidimos traérselo también (al final, ojo está en inglés) para que tengan la idea de donde sale esto. La traducción no es mía, es de Jorge. Pueden encontrar el blog del autor aquí. Hoy es viernes, así que feliz fin de semana y provecho!

Una posible respuesta al debate de multitarea.
Acabo de ver un vídeo acerca de la Interfaz de usuario de un Blackberry Playbook. Entre muchas cosas interesantes un pequeño detalle atrajo mi atención: y es que la forma en que el dispositivo realiza la multitarea es dejado a elección del usuario, como el tablet que puede realizar multitarea de dos formas diferentes.
  • Solo las tareas del sistema pueden correr en segundo plano, las aplicaciones se congelan o se cierran cuando pasan a este estado (a la forma de IOS/ Windows Phone 7).
  • Todas las aplicaciones están corriendo constantemente (la forma de Sistemas de escritorio/ Symbian/Android)
El hecho de que los ingenieros (de RIM) hayan dejado ambas opciones es bien interesante, esto significa que no encontraron la respuesta correcta al problema de la multitarea y de echo existe un debate activo sobre como debe hacerse la multitarea. Y aun cuando la discusión en su mayoría es sobre dispositivos móviles, la evolución de la multitarea podría beneficiar a los computadores personales también. En este artículo haremos una revisión profunda de este tema y sugeriremos cual vía será la más correcta para realizar la multitarea  en estos sistemas operativos.

Dos enfoques principales y un compromiso errado.
A primera vista, esto parece un cisma fundamental.
Los defensores del “frozen background” (las tareas en segundo plano quedan "congeladas" ndt) plantean que los usuarios interactúan con una sola aplicación en un instante de tiempo, y por tanto es natural detener los procesos que corren en segundo plano con el objetivo de ahorrar batería, mejorar el rendimiento, y evitar sobrecargar la mente del usuario. Tomemos como ejemplo lo que sucede en un teléfono cuando llega un SMS y el usuario está viendo un vídeo o jugando un vídeo juego, acaso el usuario debe manualmente pausar el vídeo o el juego antes de leer el SMS, o debe pasar a el SMS mientras el resto de las aplicaciones son pausadas en silencio.
Los defensores del “always on” (todo se ejecuta, este o no en primer plano ndt) plantean que congelar las aplicaciones sin preguntar interrumpe algunos comportamientos deseables. Invocan el ejemplo de los reproductores de sonido que corren segundo plano mientras el usuario redacta un mensaje, o el caso de las conexiones de red que deben conservarse activas para evitar logins repetitivos y frustrantes como es el caso de algunos proxys o redes VPN. Plantean incluso que uno de los principales beneficios de la multitarea es la habilidad de hacer algo mientras en el fondo se realizan cálculos o alguna descarga, un beneficio que desaparece completamente con el modelo de procesos congelados.
Obviamente en este debate ambos lados están en lo correcto por tanto se han creado compromisos. El más sencillo de estos compromisos ha sido introducido  por IOS 4, y será utilizado en la próxima actualización de "multitarea" para Windows Phone 7 hasta donde yo conozco. Consiste en permitirle a las aplicaciones dejarle una cierta cantidad de trabajo al sistema mientras están detenidas en  segundo plano. 
Por ejemplo un reproductor multimedia pudiera darle un flujo de datos de multimedia que se están reproduciendo en ese momento al sistema operativo, de modo que si lo ponemos en segundo plano el sistema será capaz de continuar reproduciendo esa información.
No es necesario ser un genio para darse cuenta que esto es solo un paliativo a las limitaciones del modelo "frozen background", que no es suficiente por una sencilla razón: y es que el fabricante del sistema decide arbitrariamente las aplicaciones que pueden trabajar en segundo plano y las que no, por tanto se enfrenta a uno de los principales desafíos que cualquiera que haya trabajado por algún tiempo en un sistema conoce: no se puede planificar todo. 
Tomemos como ejemplo las llamadas telefónicas de Skype. Dos usuarios se comunican a través una transmisión de audio encriptado por un algoritmo propietario. Para que trabaje siguiendo este modelo los fabricantes de sistemas operativos tendrían que implementar el algoritmo propietario de Skype en su sistema. Cualquier otro algoritmo que no esté explícitamente evaluado por ellos se enfrentaría al mismo problema: si nuestra aplicación quisiera utilizar un DRM que no haya sido implementado en el sistema, no podría trabajar en segundo plano. Si utilizara un códec de audio libre de derechos de autor que no este aprobado por el fabricante del sistema, no podría trabajar en segundo plano, y así sucesivamente.  
Existen dos formas en que los defensores de este enfoque pueden encarar este asunto: o introducen meticulosamente modificaciones al sistema (hacks) para cada operación que los desarrolladores deseen ver ejecutarse en segundo plano (como el famoso hack en "voip" de iOS4, utilizado por la aplicación Skype de iOS), creado así otro sistema inflado e incoherente, o se ponen su sombrero fascista y bloquean cualquier aplicación que no satisfaga el conjunto de operaciones disponibles. Como ninguna de estas opciones es deseable a largo plazo, todo parece indicar que este enfoque está llegando a su fin, y los fabricantes de sistemas tendrán que confiar un poco en sus programadores si quieren tener éxito y llegar mas lejos.
  
Confiar en los programadores pero no ciegamente.
Sin embargo, permitirles a los desarrolladores ejecutar procesos en segundo plano ciertamente no significa que la única forma decente de hacer multitarea en un dispositivo de computo personal sea simplemente ejecutar todos los hilos de todos los procesos al mismo tiempo en modo round robin. Hay tres cosas que el sistema operativo puede y en mi opinión debe hacer:
  • En equipos que trabajan con baterías, aplicar una política de administración de energía estricta a las tareas en segundo plano, para asegurarse de que no acaben la batería mientras el equipo parece estar ocioso. 
  • Asegurarse que el rendimiento de las tareas en primer plano no se vea afectado por las tareas en segundo plano.
  • Congelar las tareas que constantemente requieran la atención del usuario y no tengan que hacer nada mas, como ver una película o jugar un vídeo juego, cuando son puestas en segundo plano.
Los dos primeros elementos conforman en conjunto un interesante problema de planificación. Los diseñadores de sistemas tendrían que comenzar con el concepto de "tareas en primer plano" con la cual el usuario estaría interactuando en ese momento, y encontrar la manera de asociarla automáticamente a un número de hilos. Esos hilos serían marcados como hilos primarios y tratados de manera diferente por el sistema operativo. Una  prioridad mayor es el mínimo posible, pero con la colaboración de los desarrolladores de sistemas y/o un adecuado y amplio uso de APIs del Sistema, es posible hacer más. Como ejemplo tomemos las tareas que son programadas para correr a intervalos regulares, pueden correr menos frecuentemente. Las tareas que no necesitan corren en segundo plano pudieran ser completamente congeladas, como es el caso de las recientes publicaciones del reproductor de Flash (Flash Player) donde la renderización de los gráficos se detiene cuando el video esta en una pestaña en segundo plano y así sucesivamente.
El truco es que uno no debe optimizar muy agresivamente. Como un ejemplo simple, si un hilo reproduce o graba un flujo de audio, incluso si es de un proceso en segundo plano, es de hecho una tarea primaria y tiene los requerimientos correspondientes (de una tarea primaria, la reproducción/grabación no deben saltarse)
Imagine por ejemplo una comunicación vocal donde las personas programan una cita mientras miran su calendario: la llamada telefónica debe permanecer en prioridad máxima, con buena calidad de comunicación sin que se caiga la conexión.
Cuando las aplicaciones utilizan APIs del sistema, podemos separar  sencillamente las tareas primarias de las secundarias implementando estas nociones en el núcleo de las mencionadas APIs. Pero como el ejemplo anterior de iOS 4 muestra, las APIs del sistema no pueden manejar las necesidades de todas las aplicaciones, y no podemos esperar que todas las aplicaciones la utilicen aun cuando deberían hacerlo. Así tenemos que proveer un mecanismo para las aplicaciones que hacen las cosas a su manera, permitiéndoles informarle al programador del sistema de sus acciones y así ayudarle a decidir. Preferiblemente, este mecanismo debería dirigirse al tercer aspecto mencionado anteriormente, permitiéndole a las tareas con alta interacción ser congeladas cuando pasen a segundo plano.
Y esta es el área donde se debería confiar en los desarrolladores.

Políticas de programación de hilos.
Estamos hablando de multitarea así que el principal objeto no son los procesos sino los hilos. En el esquema que se describió arriba, un hilo en segundo plano puede tener tres comportamientos cualitativos (que pueden aparecer de diferentes formas):
  • Primer Plano: prioridad máxima, consumo total de los recursos, así es como se trata un hilo de una aplicación que esta actualmente en uso.
  • Daemon (demonio, vean la referencia ndt): A pesar de que el hilo esta corriendo aun, no se le considera importante por el sistema y se le aplica una política agresiva de administración de energía, acceso a la red y tiempo de CPU  para asegurarse que no afecte el rendimiento de ninguna tarea corriendo en primer plano y para reducir su impacto sobre el uso de la batería, si existe alguna. Este es el estado en que se encuentran la mayoría de los servicios en segundo plano.
  • Bloqueado (Congelado): El hilo no está activo. Conveniente para hilos que solo son útiles cuando interactúan directamente con el usuario, como vídeo juegos o paquetes de Ofimática. 
De ahí, inmediatamente extraemos nuestras tres políticas de programación, especificando como deben tratarse los hilos cuando están en segundo plano: podrán ser tratados como tareas primarias (Ej: transmisiones de audio), servicios o demonios (Ej: descargas, VPN, cálculos, servicios como clientes de correo o SMS), o tareas bloqueadas (Ej: videojuegos)
Un desarrollador que sabe que esta haciendo debe ser capaz de seleccionar una política de programación por si mismo. En sistemas como C, esto debería trabajar de esta forma:

Si el hilo está creado usando algo como esto ... 

Thread* t = createThread();

... Entonces podríamos ofrecer un parámetro que invalide la política por defecto, de esta forma...

Thread* t = createThread(schedForeground);

... u ofrecer una forma de modificar la política de programación del hilo posteriormente a través de una función específica, como esta:

setSchedulingPolicy(t, schedForeground);

Y ahora es el momento de la gran pregunta: cuando el sistema no puede tomar decisiones de programación basadas en llamadas a API y el dispositivo no especifica nada, ¿que debe tomarse como política por defecto? ¿Demonio o bloqueado? Sin embargo nos la hemos arreglado para producir algo que trabaje en todas las situaciones, terminaremos analizando una variante del problema anterior.
Mi idea es colocar las tareas en segundo plano en modo de servicio (demonio) por defecto, porque esto refleja la forma en que trabaja el mundo en que vivimos. Las cosas en movimiento no se detienen porque paremos de mirarlas, sin embargo los bebes están bastante convencidos de ello. ¿Entonces por que los hilos deberían comportarse así? Existen casos en los que eso es efectivo, pero no debería ser la opción por defecto, dado que otros desarrolladores sin experiencia convertirían este sistema en otro iOS donde los procesos son detenidos tan pronto como dejes de mirarlos.