web-dev-qa-db-fra.com

Comment créer une méthode asynchrone

J'ai une méthode simple dans mon application C #, il sélectionne un fichier sur un serveur FTP, le analyse et stocke les données dans une base de données. Je veux que ce soit asynchrone, de sorte que l'utilisateur effectue d'autres opérations sur App. Une fois l'analyse terminée, il doit recevoir un message indiquant que "l'analyse est terminée".

Je sais que cela peut être réalisé par un appel de méthode asynchrone mais je ne sais pas comment faire cela quelqu'un peut-il m'aider s'il vous plaît?

51
Prashant C

Vous devez utiliser les délégués et la méthode BeginInvoke qu'ils contiennent pour exécuter une autre méthode de manière asynchrone. A la fin de la méthode en cours d’exécution par le délégué, vous pouvez en informer l’utilisateur. Par exemple:

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

Lisez à http://msdn.Microsoft.com/en-us/library/2e08f6yc.aspx

75
Callum Rogers

essayez cette méthode

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

Usage:

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

Chaque fois que vous effectuez une opération asynchrone, vous utilisez un thread distinct, soit un nouveau thread, soit un extrait du pool de threads. Cela signifie que tout ce que vous faites de manière asynchrone doit faire très attention aux interactions avec d'autres threads.

Une façon de le faire est de placer le code du thread async (appelez-le thread "A") avec toutes ses données dans une autre classe (appelez-le class "A"). Assurez-vous que le fil "A" n'accède qu'aux données de la classe "A". Si le fil "A" ne touche que la classe "A" et qu'aucun autre fil ne touche les données de la classe "A", il y a un problème de moins:

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

Notez que la seule partie de AsyncClass qui est touchée de l'extérieur est son interface publique, et la seule partie de celle qui contient des données est CompletionTime. Notez que ceci est seulement touché après la fin de la tâche asynchrone. Cela signifie que rien d'autre ne peut interférer avec le fonctionnement interne des tâches et qu'il ne peut interférer avec rien d'autre.

6
John Saunders

Voici deux liens sur le threading en C #

Je commencerais à lire sur la classe BackgroundWorker

4
tanascius

Dans Asp.Net, j'utilise beaucoup de méthodes static pour les travaux à effectuer. Si c’est simplement un travail pour lequel j’ai besoin de pas de réponse ou de statut, je fais quelque chose de simple comme ci-dessous. Comme vous pouvez le constater, je peux choisir d'appeler ResizeImages ou ResizeImagesAsync, selon que je souhaite attendre la fin ou non.

Explication de code: j'utilise http://imageresizing.net/ pour redimensionner/rogner des images et la méthode SaveBlobPng consiste à stocker les images dans Azure (nuage), mais cela n'a aucune importance pour cette démonstration. t inclure ce code. C’est un bon exemple de tâches fastidieuses}

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

Ou aller pour le filetage afin que vous n'ayez pas à vous soucier des délégués

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

ThreadPool.QueueUserWorkItem est le moyen le plus rapide d’exécuter un processus sur un autre thread. 

Sachez que les objets d'interface utilisateur ont une "affinité de thread" et que vous ne pouvez y accéder qu'à partir d'un thread autre que celui qui les a créés.

Ainsi, en plus d'extraire ThreadPool (ou d'utiliser le modèle de programmation asynchrone via des délégués), vous devez extraire Dispatchers (wpf) ou InvokeRequired (winforms).

1
Will

En fin de compte, vous devrez utiliser une sorte de filetage. La façon dont cela fonctionne est que vous démarrez une fonction avec un nouveau thread et qu'elle s'exécutera jusqu'à la fin de la fonction.

Si vous utilisez Windows Forms, un wrapper de Nice qu’ils ont pour cela est appelé Background Worker. Il vous permet de travailler en arrière-plan sans verrouiller le formulaire de l'interface utilisateur et constitue même un moyen de communiquer avec les formulaires et de fournir des événements de mise à jour de progression.

Travailleur de fond

0
QueueHammer

.NET a obtenu le nouveau mot clé async pour les fonctions asymétriques. Vous pouvez commencer à creuser dans docs.Microsoft.com (async) . Le plus court général pour rendre la fonction asymétrique est de changer de fonction F:

Object F(Object args)
{
    ...
    return RESULT;
}

à quelque chose comme ça:

async Task<Object> FAsync(Object args)
{
    ...
    await RESULT_FROM_PROMISE;
    ...
    return RESULT;
}

La chose la plus importante dans le code ci-dessus est que, lorsque votre code approche de wait, il renvoie le contrôle à une fonction appelée FAsync et effectue d'autres calculs jusqu'à ce que la valeur promise soit renvoyée et procède avec le reste du code dans fonction FAsync.

0
Piotr Wojcik