2009-07-21 16 views
51

Tengo un método simple en mi aplicación C#, selecciona el archivo del servidor FTP y lo analiza y almacena en DB. Quiero que sea asíncrono, para que el usuario realice otras operaciones en la aplicación, una vez que haya finalizado el análisis, debe obtener el mensaje que dice "El análisis está hecho".Cómo crear un método asíncrono

Sé que se puede lograr a través de la llamada al método asíncrono pero No sé cómo hacerlo ¿Alguien me puede ayudar por favor?

+0

Sólo Quería mencionar: hay 2 formas de realizar llamadas asíncronas: con hilos y con delegados. –

+0

Es muy simple. Usted crea un delegado. Asignarle tu función y luego realizar una llamada asíncrona. [Este] (http://msdn.microsoft.com/en-us/magazine/cc301332.aspx) artículo lo describe muy bien (también le enseña qué es un delegado). –

+1

¿El enlace no funcionó para mí? –

Respuesta

4

Aquí hay dos enlaces sobre el roscado en C#

me gustaría empezar a leer sobre el BackgroundWorker class

+0

Gracias por su respuesta, ¿es posible hacerlo sin hilos, puede ser con delegados? –

+0

Puede usar un BeginInvoke(), pero eso invoca otro hilo también. Realmente, eche un vistazo al BackgroundWorker: es fácil de usar y proporciona una notificación cuando se realiza el trabajo. – tanascius

74

Es necesario utilizar delegados y la BeginInvoke método que contienen para ejecutar otro método de forma asincrónica. A al final del método que está ejecutando el delegado, puede notificar al usuario. Por ejemplo:

class MyClass 
{ 
    private delegate void SomeFunctionDelegate(int param1, bool param2); 
    private SomeFunctionDelegate sfd; 

    public MyClass() 
    { 
     sfd = new SomeFunctionDelegate(this.SomeFunction); 
    } 

    private void SomeFunction(int param1, bool param2) 
    { 
     // Do stuff 

     // Notify user 
    } 

    public void GetData() 
    { 
     // Do stuff 

     sfd.BeginInvoke(34, true, null, null); 
    } 
} 

leer en http://msdn.microsoft.com/en-us/library/2e08f6yc.aspx

+18

Tenga en cuenta que en lugar de declarar y utilizar un 'SomeFunctionDelegate' puede simplemente usar' Action 'y de manera similar un' Func 'para los métodos que no son nulos. –

+2

nueva Acción (MethodName) .BeginInvoke (1, "texto", nulo, nulo); –

+0

** esto es delegados asincrónicos y métodos no asíncronos **. Los métodos asíncronos siguen un protocolo similar externamente, pero existen para resolver un problema mucho más difícil –

1

ThreadPool.QueueUserWorkItem es la manera más rápida de conseguir un proceso que se ejecuta en un hilo diferente.

Tenga en cuenta que los objetos de la interfaz de usuario tienen "afinidad de subprocesos" y no se puede acceder a ellos desde ninguna cadena que no sea la que los creó.

Por lo tanto, además de verificar el ThreadPool (o utilizar el modelo de programación asincrónica por medio de delegados), debe verificar Dispatchers (wpf) o InvokeRequired (winforms).

+0

Si alguien necesita acceder a los elementos de la IU creados en otro hilo (excepciones de hilos cruzados), consulte esta gran publicación: http://stackoverflow.com/questions/142003/cross-thread-operation-not-valid-control-accessed -de-un-thread-otro-que-el-t –

6

Cada vez que haga algo asincrónico, está utilizando un hilo separado, ya sea un hilo nuevo o uno tomado del grupo de hilos. Esto significa que cualquier cosa que hagas asincrónicamente tiene que ser muy cuidadoso con las interacciones con otros hilos.

Una forma de hacerlo es colocar el código para el hilo asincrónico (llámalo hilo "A") junto con todos sus datos en otra clase (llámalo clase "A"). Asegúrese de que el hilo "A" solo acceda a los datos en la clase "A". Si el hilo "A", sólo toca la clase "A", y ningún otro hilo toca clase "A" 's de datos, entonces hay un problema menos:

public class MainClass 
{ 
    private sealed class AsyncClass 
    { 
     private int _counter; 
     private readonly int _maxCount; 

     public AsyncClass(int maxCount) { _maxCount = maxCount; } 

     public void Run() 
     { 
      while (_counter++ < _maxCount) { Thread.Sleep(1); } 
      CompletionTime = DateTime.Now; 
     } 

     public DateTime CompletionTime { get; private set; } 
    } 

    private AsyncClass _asyncInstance; 
    public void StartAsync() 
    { 
     var asyncDoneTime = DateTime.MinValue; 
     _asyncInstance = new AsyncClass(10); 
     Action asyncAction = _asyncInstance.Run; 
     asyncAction.BeginInvoke(
      ar => 
       { 
        asyncAction.EndInvoke(ar); 
        asyncDoneTime = _asyncInstance.CompletionTime; 
       }, null); 
     Console.WriteLine("Async task ended at {0}", asyncDoneTime); 
    } 
} 

en cuenta que la única parte de AsyncClass que ha tocado desde el exterior es su interfaz pública, y la única parte de eso que es datos es CompletionTime. Tenga en cuenta que esto es solo que se toca después de que se completa la tarea asincrónica. Esto significa que nada más puede interferir con el funcionamiento interno de las tareas y no puede interferir con ninguna otra cosa.

+2

Esa cadena "tarea asíncrona terminada en {0}" no se imprime después de que finaliza la tarea asincrónica ... – Jacob

+2

Por favor, corrija su enunciado "Cada vez que lo haga algo asincrónico, estás usando un hilo separado ". Está mal. Verifique [Asynchrony en C# 5.0 parte cuatro: no es mágico] (http://blogs.msdn.com/b/ericlippert/archive/2010/11/04/asynchrony-in-c-5-0-part-four- it-s-not-magic.aspx) –

+0

Siempre es un hilo _separate_, lógicamente, incluso si, físicamente, el mismo hilo se puede reutilizar. –

0

Al final, tendrá que usar algún tipo de enhebrado. La forma en que funciona básicamente es que inicias una función con un nuevo hilo y se ejecutará hasta el final de la función.

Si está utilizando Windows Forms entonces un buen envoltorio que tienen para esto es llamar al Trabajador de Antecedentes. Le permite trabajar en segundo plano sin bloquear el formulario de UI e incluso proporciona una forma de comunicarse con los formularios y proporcionar eventos de actualización de progreso.

Background Worker

4

En Asp.Net uso un montón de métodos estáticos para los trabajos a realizar. Si es simplemente un trabajo donde necesito sin respuesta o estado, hago algo simple como a continuación. Como se puede ver que puedo optar por llamar a cualquiera ResizeImages o ResizeImagesAsync dependiendo si quiero esperar a que termine o no

explicación Código: Consumo http://imageresizing.net/ cambiar el tamaño de las imágenes/de los cultivos y el método SaveBlobPng es almacenar las imágenes a Azure (nube) pero como eso es irrelevante para esta demostración, no incluí ese código. Es un buen ejemplo de tareas que consumen tiempo, aunque

private delegate void ResizeImagesDelegate(string tempuri, Dictionary<string, string> versions); 
private static void ResizeImagesAsync(string tempuri, Dictionary<string, string> versions) 
{ 
    ResizeImagesDelegate worker = new ResizeImagesDelegate(ResizeImages); 
    worker.BeginInvoke(tempuri, versions, deletetemp, null, null); 
} 
private static void ResizeImages(string tempuri, Dictionary<string, string> versions) 
{ 
    //the job, whatever it might be 
    foreach (var item in versions) 
    { 
     var image = ImageBuilder.Current.Build(tempuri, new ResizeSettings(item.Value)); 
     SaveBlobPng(image, item.Key); 
     image.Dispose(); 
    } 
} 

o ir a rosca para que no tenga que molestarse con delegados

private static void ResizeImagesAsync(string tempuri, Dictionary<string, string> versions) 
{ 
    Thread t = new Thread (() => ResizeImages(tempuri, versions, null, null)); 
    t.Start(); 
} 
18

probar este método

public static void RunAsynchronously(Action method, Action callback) { 
    ThreadPool.QueueUserWorkItem(_ => 
    { 
     try { 
      method(); 
     } 
     catch (ThreadAbortException) { /* dont report on this */ } 
     catch (Exception ex) { 
     } 
     // note: this will not be called if the thread is aborted 
     if (callback!= null) callback(); 
    }); 
} 

Uso:

RunAsynchronously(() => { picks file from FTP server and parses it}, 
     () => { Console.WriteLine("Parsing is done"); }); 
Cuestiones relacionadas