Mostrando las entradas con la etiqueta thread. Mostrar todas las entradas
Mostrando las entradas con la etiqueta thread. Mostrar todas las entradas
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.
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
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
9/30/2018 05:25:00 p.m.
c#
,
Learning Machine
,
thread
Vamos a programar #52 - Introducción al paralelismo (Básico)
Hola de nuevo a todos, el día de hoy vamos a ver cómo es que se usan las clases en .NET para poder usar el paralelismo.
Antes que nada, ¿que es el paralelismo?
Todas las tareas las hacia de forma secuencial (una tras la otra), pero si el hardware puede hacer más, ¿porque no explotarlo cómo se debe? Actualmente los lenguajes de programación de .NET, disponen de una clase que ayuda a la hora de crear los procesos paralelos.
Para darnos una idea de cómo implementarlo, veamos el siguiente código.
Para poder usar las funciones de paralelismo, debemos de importar el espacio System.Threading.Tasks. El código simplemente calcula el número MD5 de un archivo, pero si no fijamos con detenimiento en BtnParallel_Click, veremos que hacemos uso de Parallel.For , que en su forma más simple, recibe 3 argumentos. El primero, es un valor del tipo int que servirá para indicar desde que número empezaremos la iteración, en este caso es el número 0 (porque desde ahí vamos a empezar a contar). El siguiente parámetro, también es un valor del tipo int, que se usará cómo limite para la iteración, en el caso del código anterior, indicamos que solo va a llegar hasta ItemCount que almacena el número de elementos que contiene un arreglo. Finalmente viene la acción, en este caso la creamos por medio de una expresión lambda en la cual decimos que por cada elemento, se va llamar a la función GetMd5, y a su vez el valor resultante se asignará a un elemento de la matriz HASH2, cuando termine el proceso, todos los valores se agregaran al listview principal y se mostrarán al usuario.
Los resultados los podemos ver en la siguiente imagen (hablando de rendimiento).
Mientras que de un lado tenemos que el uso del CPU está en 25% y tardo 30 segundos en calcular el HASH de algunas imágenes, del otro vemos que el uso del CPU es al 100% y además el tiempo que le tomo fue una cuarta parte del tiempo del calculo secuencial.
Para que revises bien el código, lo pongo en mi dropbox cómo de costumbre, pero cabe aclarar que es meramente ilustrativo, pero cómo introducción funciona. En futuros post veremos cómo hacer uso de las sobrecargas que tienen la misma función Parallel.for, pero además veremos cuales son las diferencia con el multi-therad tradicional (recuerdo que hice un post pero no se publicó y desapareció).
Los leo luego
Antes que nada, ¿que es el paralelismo?
El paralelismo es una forma de computación en la cual varios cálculos pueden realizarse simultáneamente, basado en el principio de dividir los problemas grandes para obtener varios problemas pequeños, que son posteriormente solucionados en paralelo. Hay varios tipos diferentes de paralelismo: nivel de bit, nivel de instrucción, de datos y de tarea. El paralelismo ha sido empleado durante muchos años, sobre todo para la Computación de alto rendimiento. Wikipedia/paralelismo.Aplicado a los términos de la programación tradicional, el paralelismo significa crear varias tareas que se ejecutan de forma simultanea, en el caso de los sistemas de computo moderno, la gran mayoría de ellos disponen de más de un procesador (9~12 núcleos en el mejor de los casos para el computo casero), pero a la hora de hacer cálculos, al menos en mi caso, nunca me preocupe por usar el mayor poder de computo disponible.
Todas las tareas las hacia de forma secuencial (una tras la otra), pero si el hardware puede hacer más, ¿porque no explotarlo cómo se debe? Actualmente los lenguajes de programación de .NET, disponen de una clase que ayuda a la hora de crear los procesos paralelos.
Para darnos una idea de cómo implementarlo, veamos el siguiente código.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Security.Cryptography;
using System.Threading.Tasks;
namespace PruebaParalelo
{
public partial class FrmMain : Form
{
private FileInfo[] Archivos;
private string GetMd5(string filename)
{
StringBuilder SBuild = new StringBuilder();
using (var md5 = MD5.Create())
{
using (var stream = File.OpenRead(filename))
{
byte[] Data = md5.ComputeHash(stream);
for (int i = 0; i < Data.Length; i++)
{
SBuild.Append(Data[i].ToString("x2"));
}
return SBuild.ToString();
}
}
}
public FrmMain()
{
InitializeComponent();
}
private void BtnAddFiles_Click(object sender, EventArgs e)
{
string Path;
using(FolderBrowserDialog FolderDialog = new FolderBrowserDialog())
{
FolderDialog.Description = "Selecciona un folder con archivos";
if (FolderDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
Path = FolderDialog.SelectedPath;
DirectoryInfo di = new DirectoryInfo(Path + "\\");
Archivos = di.GetFiles("*.*", SearchOption.AllDirectories);
foreach (FileInfo Archivo in Archivos)
{
LVFiles.Items.Add(Archivo.FullName);
}
}
}
}
private void BtnParallel_Click(object sender, EventArgs e)
{
string[] HASH2;
int ItemCount = Archivos.Length;
HASH2 = new string[Archivos.Length];
int j = 0;
try
{
Parallel.For(0, ItemCount, (i) =>
{
HASH2[i] = GetMd5(Archivos[i].FullName);
}
);
foreach (FileInfo Archivo in Archivos)
{
LVFiles.Items[j].SubItems.Add(HASH2[j]);
j++;
}
}
catch
{
}
}
}
}
Para poder usar las funciones de paralelismo, debemos de importar el espacio System.Threading.Tasks. El código simplemente calcula el número MD5 de un archivo, pero si no fijamos con detenimiento en BtnParallel_Click, veremos que hacemos uso de Parallel.For , que en su forma más simple, recibe 3 argumentos. El primero, es un valor del tipo int que servirá para indicar desde que número empezaremos la iteración, en este caso es el número 0 (porque desde ahí vamos a empezar a contar). El siguiente parámetro, también es un valor del tipo int, que se usará cómo limite para la iteración, en el caso del código anterior, indicamos que solo va a llegar hasta ItemCount que almacena el número de elementos que contiene un arreglo. Finalmente viene la acción, en este caso la creamos por medio de una expresión lambda en la cual decimos que por cada elemento, se va llamar a la función GetMd5, y a su vez el valor resultante se asignará a un elemento de la matriz HASH2, cuando termine el proceso, todos los valores se agregaran al listview principal y se mostrarán al usuario.
Los resultados los podemos ver en la siguiente imagen (hablando de rendimiento).
Mientras que de un lado tenemos que el uso del CPU está en 25% y tardo 30 segundos en calcular el HASH de algunas imágenes, del otro vemos que el uso del CPU es al 100% y además el tiempo que le tomo fue una cuarta parte del tiempo del calculo secuencial.
Para que revises bien el código, lo pongo en mi dropbox cómo de costumbre, pero cabe aclarar que es meramente ilustrativo, pero cómo introducción funciona. En futuros post veremos cómo hacer uso de las sobrecargas que tienen la misma función Parallel.for, pero además veremos cuales son las diferencia con el multi-therad tradicional (recuerdo que hice un post pero no se publicó y desapareció).
Los leo luego
5/06/2018 06:26:00 p.m.
aprende
,
c#
,
parallel
,
programacion
,
thread
Vamos a programar #47 - Co-Rutinas en LUA.
Hola de nuevo a todos, el día de hoy vamos a ver un poco sobre el lenguaje de programación LUA.
Antes que nada, debo de aclarar que este no es un tutorial para aprender a programar en Lua, en este post solo explicaré cómo hacer uso de las co-rutinas. Probablemente en el futuro, habrá un ecuatorial completo en las series "Learning machine", pero por ahora y por petición de un amigo mio, veremos cómo es que se hace uso de ellas. Eso no nos impedirá ver lo básico, ¿Que es Lua?; bueno, lua es un lenguaje de programación interpretado; es decir, a diferencia de lenguajes cómo C o C#, este, no es necesario compilarlo para usarlo, una vez escrito el código fuente, se puede pasar al interprete (que será el ejecutable) y este interpretará el código y producirá un resultado, si es necesario cambiar alguna parte del programa, en lugar de volver a compilar el ejecutable, bastará con modificar el código fuente.
En lua, la manera sencilla de crear una co-rutina, es haciendo uso de "coroutine.create()" y en su forma más sencilla, debemos de pasar una función cómo parámetro. para poder interactuar con la función, dentro de esta, debe de haber algo que diga "oye, tengo que decir algo", la función "coroutine.yield()" se encarga de hacer eso, finalmente, debemos de tener una parte que escuche y para eso existe "coroutine.resume()". Si tomamos cómo ejemplo el código anterior, vemos que hay que crear la funcion y esta debe de contener la "interrupción", en este caso "coroutine.yield()" la manera en que lua trabaja con las co-rutinas, es interrumpiendo, es decir si estamos ejecutando un trozo de código, este normalmente se ejecutará de forma lineal hasta el final, pero si usamos las co-rutinas, cuando observamos en el segundo bucle, y en general cuando se encuentre con la instrucción "coroutine.resume()", la ejecución pasará a la co-rutina y esta se ejecutará hasta que se encuentre con "coroutine.yield()", cuando se encuentra con esta instrucción, la ejecución continuará con la linea inmediata después de "coroutine.resume()".
Para poder apreciar mejor el resultado, puedes ir a la página de lua, y probar el código anterior.
Cómo lua es un lenguaje de "scripting" es usado en varias plataformas y las funciones disponibles pueden variar, pero todas las que se usan aquí, deben de estar disponibles en la mayoría, ahora por ejemplo, si queremos cargar archivos sin bloquear la pantalla principal, podemos hacerlo usando co-rutinas. Esa seria la introducción, pero esto se puede ampliar un poco mas, en otro post.
Los leo luego.
Antes que nada, debo de aclarar que este no es un tutorial para aprender a programar en Lua, en este post solo explicaré cómo hacer uso de las co-rutinas. Probablemente en el futuro, habrá un ecuatorial completo en las series "Learning machine", pero por ahora y por petición de un amigo mio, veremos cómo es que se hace uso de ellas. Eso no nos impedirá ver lo básico, ¿Que es Lua?; bueno, lua es un lenguaje de programación interpretado; es decir, a diferencia de lenguajes cómo C o C#, este, no es necesario compilarlo para usarlo, una vez escrito el código fuente, se puede pasar al interprete (que será el ejecutable) y este interpretará el código y producirá un resultado, si es necesario cambiar alguna parte del programa, en lugar de volver a compilar el ejecutable, bastará con modificar el código fuente.
Co-rutinas.
Ahora veamos lo que nos trajo a este post, hace un tiempo, mientras un escribía código para "Play List M" (una aplicación para PSVita), un amigo vio lo que hacía y pregunto que si sabía usar lua, le dije que si, toda la aplicación esta hecha en ese lenguaje, entonces me pregunto si sabia usar las co-rutinas y si podía explicarserlas.
Las co-rutinas en lua, sirven para ejecutar código en una sección aparte, es muy similar un "thread" en c#, pero de una forma un tanto distinta. Veamos cómo es que se ejecuta un programa con un "thread" (hilo desde ahora) separado. Ahora observemos las siguientes imágenes.
![]() |
| Esta es la representación más simple de un programa |
![]() |
| Esta es la representación más simple de un programa con un hilo adicional. |
La ventaja de tener un hilo secundario, es que la aplicación no se bloqueara mientras haga un trabajo difícil (o haga un ciclo o un bucle), si los resultados no son necesarios para continuar con la ejecución del programa, podemos hacer otra tarea mientras el código del otro hilo termina.
En el caso de lua, cuando hablamos de co-rutinas, no significa que creemos otro hilo, para observar a detalle lo que ocurre, tomemos el siguiente código:
local counter = 1; local function OneToHoundred() while counter < 50 do io.write("Contador:"..counter.."\n"); coroutine.yield(); counter = counter + 1; end end CoProc = coroutine.create(OneToHoundred); local counter2 = 0; while counter2 < 101 do coroutine.resume(CoProc); io.write("Contador2:"..counter2.."\n"); counter2= counter2 + 1; end
En lua, la manera sencilla de crear una co-rutina, es haciendo uso de "coroutine.create()" y en su forma más sencilla, debemos de pasar una función cómo parámetro. para poder interactuar con la función, dentro de esta, debe de haber algo que diga "oye, tengo que decir algo", la función "coroutine.yield()" se encarga de hacer eso, finalmente, debemos de tener una parte que escuche y para eso existe "coroutine.resume()". Si tomamos cómo ejemplo el código anterior, vemos que hay que crear la funcion y esta debe de contener la "interrupción", en este caso "coroutine.yield()" la manera en que lua trabaja con las co-rutinas, es interrumpiendo, es decir si estamos ejecutando un trozo de código, este normalmente se ejecutará de forma lineal hasta el final, pero si usamos las co-rutinas, cuando observamos en el segundo bucle, y en general cuando se encuentre con la instrucción "coroutine.resume()", la ejecución pasará a la co-rutina y esta se ejecutará hasta que se encuentre con "coroutine.yield()", cuando se encuentra con esta instrucción, la ejecución continuará con la linea inmediata después de "coroutine.resume()".
Para poder apreciar mejor el resultado, puedes ir a la página de lua, y probar el código anterior.
Cómo lua es un lenguaje de "scripting" es usado en varias plataformas y las funciones disponibles pueden variar, pero todas las que se usan aquí, deben de estar disponibles en la mayoría, ahora por ejemplo, si queremos cargar archivos sin bloquear la pantalla principal, podemos hacerlo usando co-rutinas. Esa seria la introducción, pero esto se puede ampliar un poco mas, en otro post.
Los leo luego.
3/04/2018 04:05:00 p.m.
aprende
,
co-rutinas
,
lua
,
programacion
,
thread
Suscribirse a:
Entradas
(
Atom
)










