2009-07-21 2 views
51

Ho un metodo semplice nella mia app C#, preleva il file dal server FTP e lo analizza e memorizza i dati nel DB. Voglio che sia asincrono, in modo che l'utente esegua altre operazioni su App, una volta che l'analisi è terminata, deve ricevere il messaggio "L'analisi è terminata".Come creare un metodo asincrono

So che può essere raggiunto tramite la chiamata al metodo asincrono ma Non so come fare che qualcuno può aiutarmi per favore ??

+0

Solo voluto menzionare - ci sono 2 modi per eseguire chiamate asincrone: con thread e con delegati. –

+0

È molto semplice. Si crea un delegato. Assegna la tua funzione ad esso e poi fai una chiamata asincrona. [Questo] (http://msdn.microsoft.com/en-us/magazine/cc301332.aspx) articolo lo descrive molto bene (ti insegna anche cosa è un delegato). –

+1

Link non ha funzionato per me ?? –

risposta

4

Qui ci sono due i collegamenti con filettatura in C#

mi piacerebbe iniziare a leggere la BackgroundWorker class

+0

Grazie per la risposta, è possibile farlo senza discussioni, potrebbe essere con i delegati? –

+0

È possibile utilizzare BeginInvoke(), ma invoca anche un altro thread. Davvero, date un'occhiata a BackgroundWorker: è facile da usare e fornisce una notifica quando il lavoro è finito. – tanascius

74

È necessario utilizzare i delegati e il BeginInvoke metodo che contengono per eseguire un altro metodo in modo asincrono. Alla fine del metodo gestito dal delegato, puoi avvisare l'utente. Per esempio:

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); 
    } 
} 

leggere fino a http://msdn.microsoft.com/en-us/library/2e08f6yc.aspx

+18

Nota che invece di dichiarare e usare 'SomeFunctionDelegate' puoi semplicemente usare un 'Action ' e similmente un' Func 'per metodi che non sono nulli. –

+2

new Action (MethodName) .BeginInvoke (1, "text", null, null); –

+0

** questo è delegati asincroni e non asincroni metodi ** metodi asincroni seguono un protocollo simile esteriormente, ma esistono per risolvere un molto problema più difficile –

1

ThreadPool.QueueUserWorkItem è il modo più rapido per ottenere un processo in esecuzione su un thread diverso.

Tenere presente che gli oggetti dell'interfaccia utente hanno un'affinità di thread e non è possibile accedervi da alcun thread diverso da quello che li ha creati.

Quindi, oltre a verificare il ThreadPool (o utilizzare il modello di programmazione asincrona tramite delegati), è necessario verificare Dispatchers (wpf) o InvokeRequired (winform).

+0

Se qualcuno deve accedere agli elementi dell'interfaccia utente creati su un altro thread (eccezioni cross-thread), vedere questo ottimo post: http://stackoverflow.com/questions/142003/cross-thread-operation-not-valid-control-accessed -from-a-thread-other-the-t –

6

Ogni volta che si sta eseguendo un'operazione asincrona, si utilizza un thread separato, un nuovo thread o uno preso dal pool di thread. Ciò significa che tutto ciò che fai in modo asincrono deve essere molto attento alle interazioni con altri thread.

Un modo per farlo è inserire il codice per il thread asincrono (chiamarlo thread "A") insieme a tutti i suoi dati in un'altra classe (chiamarlo classe "A"). Assicurati che il thread "A" acceda solo ai dati della classe "A". Se il thread "a" tocca solo di classe "A", e nessun altro thread tocca classe "A" s 'i dati, poi c'è uno meno problema:

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); 
    } 
} 

Si noti che l'unica parte del AsyncClass che ha toccato dall'esterno è la sua interfaccia pubblica e l'unica parte di ciò che è dati è CompletionTime. Si noti che questo è solo toccato dopo il completamento dell'attività asincrona. Ciò significa che nient'altro può interferire con i compiti interni e non può interferire con nient'altro.

+2

Questa stringa "Async task ended at {0}" non viene stampata dopo il completamento dell'attività async ... – Jacob

+2

Plz corregge la frase "Ogni volta che si sta facendo qualcosa di asincrono, stai usando un thread separato ". È sbagliato. Controlla [Asincronia in C# 5.0 parte Quattro: Non è magico] (http://blogs.msdn.com/b/ericlippert/archive/2010/11/04/asynchrony-in-c-5-0-part-four- it-s-not-magic.aspx) –

+0

È sempre un thread _separate_, logicamente, anche se, fisicamente, è possibile riutilizzare lo stesso thread. –

0

Alla fine sarà necessario utilizzare una sorta di threading. Il modo in cui funziona fondamentalmente è che si avvia una funzione con un nuovo thread e verrà eseguita fino alla fine della funzione.

Se si utilizza Windows Form, un simpatico wrapper che hanno per questo è chiamato Background Worker. Ti consente di lavorare in background senza bloccare il modulo di interfaccia utente e fornisce anche un modo per comunicare con i moduli e fornire eventi di aggiornamento del progresso.

Background Worker

4

in Asp.Net io uso un sacco di statici metodi di posti di lavoro da fare. Se è semplicemente un lavoro in cui ho bisogno di nessuna risposta o stato, faccio qualcosa di semplice come di seguito. Come si può vedere che posso scegliere di chiamare sia ResizeImages o ResizeImagesAsync a seconda se voglio aspettare che finisca o no

spiegazione Codice: Io uso http://imageresizing.net/ per ridimensionare le immagini/colture e il metodo SaveBlobPng è quello di memorizzare le immagini ad Azure (cloud) ma dato che è irrilevante per questa demo non ho incluso quel codice. La sua un buon esempio di attività che richiede tempo se

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 andare per la filettatura modo da non dover perdere tempo con i delegati

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

provare questo metodo

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"); });