miércoles, 28 de enero de 2009

Clase timeout c# - mejoras

La clase para controlar el timeout expuesta hace casi un año (aquí) en este blog tiene un problemilla; el rendimiento no es bueno llegado el caso de que este sea un requerimiento ó se use de forma masiva. La razón es que se crea una nueva hebra por cada llamada. Para mejorarla se puede hacer un cambio en cada una de las clases envoltura; en lugar de crear una nueva hebra podemos hacer una llamada asíncrona, que utiliza en el fondo el ThreadPool de .net. De esta forma no tenemos la penalización de crear/destruir hebras, pues el framework recicla en cada llamada una hebra del ThreadPool para atender nuestra llamada.
Como no es cuestión de escribir aquí de nuevo todo el código, se expone como quedaría la clase envoltura para el caso de recibir un parámetro: Envoltura<T, U>
Habría que hacer el correspondiente cambio en las demás clases envoltura.

internal class Envoltura<T, U>
{
private Exception ex = null;
private U parametro;
private Func<T, U> metodo;
private T retorno;
Thread hebra_a_matar = null;

public Envoltura(U parametro)
{
this.parametro = parametro;
}
public T Run(Func<T, U> metodo, int milisegundos)
{
this.metodo = metodo;
ThreadStart delegado = run;
IAsyncResult result = delegado.BeginInvoke(null, null);
if (result.AsyncWaitHandle.WaitOne(milisegundos,true))
{
delegado.EndInvoke(result);
if (this.ex != null)
throw this.ex;
return this.retorno;
}
else
{
hebra_a_matar.Abort();
TimeoutSException to = new TimeoutSException();
to.Timeout = milisegundos;
throw to;
}
}
private void run()
{
try
{
hebra_a_matar = Thread.CurrentThread;
this.retorno = metodo(parametro);
}
catch (Exception e)
{
ex = e;
}
}
}

1 comentario: