Learning Machine #12 - Diseño de aplicaciones multi-hilo

Hola de nuevo a todos. En ocasiones anteriores hemos hecho aplicaciones que están compuestas por varios procesos. Pero antes de avanzar, veremos que tipo de multi-hilo es el más conveniente dependiendo de que tarea queramos realizar.


En post anteriores hemos visto que hay tareas que requieren una tiempo de procesamiento largo; dependiendo del caso, hay situaciones en las que el usuario podrá seguir trabajando ya que no depende del resultado de la computación. En otros casos no es así, ya que se depende mucho de los datos resultantes.

Cuando nos encontramos en la primer situación, podemos informar o no que es lo que está sucediendo, pero cuando se presenta la segunda, por lo general es importante hacerlo. En alguna ocasión en un post, mostré cómo es que las barras de progreso suelen ser meros placebos ya que hay una serie de factores que afectan el tiempo en que cada calculo se hace (cuantas veces no hemos visto el famoso "Restan cero segundos" o "Progreso 100%" que dura más que todo lo anterior). Ahora pra entender un poco, veremos cada caso.

Caso uno: "no necesito los datos".

Ahora veremos un ejemplo, para eso modificaremos un poco el programa en C# que prueba la conjetura de Collatz. para empezar veamos el código.
using System;
using System.Windows.Forms;
using System.Numerics;
using System.Threading;

namespace ConjeturaDeCollatz
{
	public partial class FrmMain : Form
	{
		private delegate void UpdateListDelegate(string Value);

		private void UpdateList(string Value)
		{
			if (LBResults.InvokeRequired)
			{
				LBResults.Invoke(new UpdateListDelegate(UpdateList), Value);
			}
			else
			{
				LBResults.Items.Add(Value);
			}
		}
		private void CalculateCollatz(string Number)
		{
			BigInteger MyNumber;
			BigInteger.TryParse(Number, out MyNumber);
			while (MyNumber > 1)
			{
				Thread.Sleep(1500);
				if (MyNumber.IsEven == false)
				{
					MyNumber = MyNumber * 3 + 1;
					UpdateList(MyNumber.ToString());
				}
				else
				{
					MyNumber = MyNumber / 2;
					UpdateList(MyNumber.ToString());
				}
			}
		}
		private void RunWork(string Number)
		{
			Thread DoWork = new Thread(new ThreadStart(() => CalculateCollatz(Number)));
			DoWork.Start();
		}
		private void RunWorkWithNoThread(string Number)
		{
			CalculateCollatz(Number);
		}
		public FrmMain()
		{
			InitializeComponent();
		}

		private void BtnStart_Click(object sender, EventArgs e)
		{
			LBResults.Items.Clear();
			RunWork(TxtNumberIn.Text);

		}

		private void BtnStart2_Click(object sender, EventArgs e)
		{
			RunWorkWithNoThread(TxtNumberIn.Text);
		}
	}
}

Para poder hacer las pruebas, modificamos un poco el código que ya teníamos y además, agregamos un botón para que la acción se ejecute pero no en un hilo separado, si hace clic en este botón, verás que la aplicacion parecerá que se bloquea e incluso si presiona muchas veces el botón de cerrar, windows te preguntará si quieres cerrar la aplicación porque esta no responde, pero no es el caso; el proceso sigue corriendo de manera "normal", pero debido a que se encuentra la ejecución dentro del bucle "while" no puede responder a las peticiones del usuario. Por lo que simplemente podemos esperar (el usuario más bien) a que todo acabe, de cualquier forma los resultados no son necesarios.


Caso dos "necesito esos datos".

Cuando los datos son necesarios, debemos de hallar una forma de informar al usuario cuando hay datos listos para usarse, para eso vamos a crear un hilo secundario, imaginemos que queremos escalar 1000 imágenes y a cada una arreglarle el color, por lo que se debe de hacer de una por una a la vez; pero solo parte del trabajo humano porque el proceso de escalar las imágenes se puede hacer poniendo todas en una cola y escalarlas y solo cuando se ha procesado la primera, abrirla para empezar a trabajar con ella y en el fondo el escalado del resto de las imágenes puede seguir ya que nos va a tomar varios minutos en ajustar  nuestra imagen a lo que necesitamos.

En alguno de los post que hemos hecho, hicimos un programa en android que se conectaba al bluetooth del Clock View (puedes ver el post), hacemos uso de dos tipos de thread, en la primera, simplemente notificábamos al usuario que se está realizando la conexión entre el dispositivo y Clock view y cuando esta se llevaba a cabo, un "thread" diferente se se ejecutaba y su función era manejar todos los datos que se transmitían desde/hacia el dispositivo y el bluetooth y mientas no se pida que la conexión se cierre (o se cierre la aplicación), este hilo seguirá corriendo en el fondo.

Y bien, por ahora es todo, el código de la conjetura de Collatz lo puedes modificar para probar el ejemplo de este post. En los siguiente post continuaremos con más programación.
Los leo luego

No hay comentarios.