IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Exception : Multiples tâches asynchrones


Sujet :

C#

  1. #1
    Membre du Club Avatar de mathisdu42
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2013
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Mars 2013
    Messages : 168
    Points : 64
    Points
    64
    Par défaut Exception : Multiples tâches asynchrones
    Bonjour, bonsoir à tous

    Pour situer le contexte, je dispose d'un projet contenant une référence de services (WCF) dans le but final de faire un petit outil de tests / bench
    sur des services ciblés.

    Concernant la structure, j'ai décidé de faire une méthode générique qui aura pour but de récupérer un service via son nom de méthode,
    ses paramètres puis d'invoker la méthode, le tout de manière asynchrone.

    Méthode générique :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
            public async Task<T> ExecuteMethod<T>(string nom, object[] param)
            {
                using var context = new SvDataServiceClient(new InstanceContext(Instance));
     
                Type type = context.GetType();
                MethodInfo methode = type.GetMethod(nom);
     
                if (methode != null)
                {
                    var parametres = methode.GetParameters();
                    if (parametres.Length == 0)
                        param = null;
                }
     
                var result = (Task<T>)methode?.Invoke(context, param);
     
                if (result != null && !result.IsFaulted) 
                    return await result;
     
                return default;
            }
    En utilisation simple, la méthode fonctionne bien. J'ai crée une autre classe que j'ai appelé ManagerCore dans laquelle j'appelle ma
    méthode générique et fais quelques tests. (Je retourne tous les résultats sous forme de JSON).

    Méthode Task d'appel de service :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
            public async Task<string[]> GetUserFiltersAsync()
            {
                var invokeMethod = new MethodInvoker(this);
                var benchMark = new BenchMark {
                    Action = "GetUserFiltersAsync",
                    Debut = DateTime.Now.Date,
                    Parametres = new object[] { 2, "SvDataObject.Poco.Article" },
                    ParametresRequis = invokeMethod.ExtractParams("GetUserFiltersAsync")
                };
     
                var BenchTime = new Stopwatch();
                BenchTime.Start();
     
                var userFilters = await invokeMethod.ExecuteMethod<UserFilter[]>(benchMark.Action, benchMark.Parametres);
     
                BenchTime.Stop();
     
                var userFiltersJson = await Task.Factory.StartNew(() => JsonConvert.SerializeObject(userFilters, Formatting.Indented));
     
                benchMark.Resultat = new object[] { userFilters.Select(x => x.FilterName) };
                benchMark.Duree = BenchTime.ElapsedMilliseconds;
                benchMark.Fin = DateTime.Now.Date;
     
                var benchJson = await Task.Factory.StartNew(() => JsonConvert.SerializeObject(benchMark, Formatting.Indented));
     
                return new[] { userFiltersJson, benchJson };
            }
    Seulement, je suis actuellement sur une feature qui servira à créer des scénarios, en gros,
    faire une succession de tâches asynchrones (appels de services). Pour ça j'ai utilisé Méthode de scénario :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
            public async Task<Dictionary<int, string>> Scenario1()
            {
                var managerCore = new ManagerCore();
                var jsonParser = new JsonParser();
     
                var tasks = new List<Task<string[]>>
                {
                    managerCore.GetUserFiltersAsync(),
                    managerCore.GetCommandeFournisseursAsync(),
                    managerCore.GetCommandeFournisseurAsync(),
                    managerCore.GetLignesCommandeFournisseursAsync(),
                    managerCore.GetOperateursAsync(),
                };
     
                await Task.WhenAll(tasks);
     
                foreach (var task in tasks) task.Dispose();
     
                return jsonParser.ParseMultipleJson(new List<string>
                {
                    tasks[0].Result[1], 
                    tasks[1].Result[1], 
                    tasks[2].Result[1], 
                    tasks[3].Result[1], 
                    tasks[4].Result[1], 
                });
            }
    Puis enfin, j'appelle la méthode de mon scénario de cette manière :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
                var scenario = await new ExecuteScenario().Scenario1();
     
                foreach (var item in scenario)
                {
                   // Récup des données du dico retourné.
                }
    Je rencontre différents problèmes :

    Le premier :

    Lorsque je démarre mon appli (winform) et que je fais un premier appel, n'importe le quel,
    il met un temps interminable à s'exécuter, pourtant la méthode passe bien (log de console) et c'est uniquement sur le premier appel.
    Et de manière aléatoire, les appels bloquent indéfiniment, j'ai beau attendre, rien ne se passe (voir ci-dessous) :
    Nom : 3.png
Affichages : 153
Taille : 7,7 Ko


    Le second (qui survient de manière aléatoire après plusieurs appels async d'un scénario ) :

    Mon application plante, principalement au niveau de la méthode générique et me retourne
    Nom : 1.png
Affichages : 125
Taille : 16,1 Ko

    Log console (Host WCF) :
    Nom : 2.png
Affichages : 139
Taille : 3,4 Ko

    Le troisième :

    Mon application plante aussi au niveau de la méthode générique mais cette fois-ci, l'erreur n'est pas la même
    et à vrai dire j'ai aucune idée d'où elle peut venir :

    Nom : 4.png
Affichages : 133
Taille : 10,2 Ko

    Dernière erreur :

    Lorsque je lance en premier un scénario (au lancement du HOST WCF), j'ai l'erreur suivante
    System.ServiceModel.FaultException`1*: 'Impossible d'utiliser le contexte lors de la création du modèle.
    L'exception peut être levée si le contexte est utilisé dans la méthode OnModelCreating ou si la même instance de contexte
    est accessible par plusieurs threads simultanément. Notez qu'il n'est pas garanti que les membres
    d'instance de DbContext et les classes associées soient thread-safe.'
    A savoir que mon ws est configuré en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single]
    J'ai l'impression que le/les problème(s) se situe(nt) au niveau du using context et de l'InstanceContext ?? A voir..

    Merci d'avoir pris le temps de lire, en espérant avoir quelques pistes.

    Merci,
    Cordialement.

  2. #2
    Expert éminent sénior

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 757
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 757
    Points : 10 697
    Points
    10 697
    Billets dans le blog
    21
    Par défaut
    Plusieurs choses :
    1. les Tasks sont disposées avant d'accéder à leur résultat. Cela peut avoir un résultat inattendu (et peut potentiellement expliquer certaines exceptions "aléatoires")
    2. mettre les Task dans une liste ne signifie pas que les taches sont exécutées de manière séquentielle ! Elles seront exécutées en parallèle
    3. le winform est un contexte particulier, dans le sens où toutes les Task sont exécutés sur le thread UI. Si ce n'est pas un prérequis (ce qui semble le cas), l'usage de .ConfigureAwait(false) peut accélérer les choses
    4. pour exécuter une tâche après une autre, il faut utiliser .ContinueWith


    Le premier point doit absolument être corrigé, puis refaire les tests. Certaines erreurs pourront être corrigées.

    Le point 3 peut expliquer les temps assez long.

    Et surtout, ne pas mélanger les async/await et les méthodes classique style Task.Wait,car cela peut générer des blocages dans un contexte winform.
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  3. #3
    Membre du Club Avatar de mathisdu42
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2013
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Mars 2013
    Messages : 168
    Points : 64
    Points
    64
    Par défaut
    Bonjour,

    Merci pour votre réponse, je reviens (un peu tard il est vrai) vers cette discussion pour la mettre à jour.
    J'ai donc pu résoudre la majorité de mes problèmes, en effet ma gestion des Tasks était mal faite, j'ai donc tout revu et migré vers WPF par la même occasion.
    Cela dit, après pas mal de doc à propos des tâches asynchrones, le .ContinueWith revient à de multiples reprises comme étant de "bas niveau" et qu'il était
    préférable d'utiliser à la place await..
    Si jamais vous avez quelques infos là dessus !

    Merci,
    Cordialement.

  4. #4
    Membre habitué
    Homme Profil pro
    Ingénieur Informatique
    Inscrit en
    Décembre 2005
    Messages
    146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur Informatique

    Informations forums :
    Inscription : Décembre 2005
    Messages : 146
    Points : 158
    Points
    158
    Par défaut
    Désolé, j'arrive après "la bataille" ^^, ravi que vous ayez su reprendre votre gestion sur les tasks.

    Toutefois, je ne comprends pas votre remarque entre continuewith et await, car ce sont deux notions différentes qui sont manipulées. De ce fait, je suis intéressé par la documentation que vous avez pu lire (si vous l'avez encore sous la main) car soit la documentation lue ne donne pas une information suffisamment explicite du sujet (qui sur le sujet des task est assez fréquent :/), soit raconte des inepties ce qui est aussi souvent le cas... ou alors c'est mon cerveau qui me joue un vilain tour . Dans tous les cas, cela m'aidera à mieux vous aider dans la compréhension entre ces deux notions, et que vous puissiez aussi communiquer dessus à l'avenir .
    Mon blog est sur https://arphonis.fr et bientôt d'autres fonctionnalités seront disponible dessus.

  5. #5
    Expert éminent sénior

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 757
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 757
    Points : 10 697
    Points
    10 697
    Billets dans le blog
    21
    Par défaut
    Citation Envoyé par mathisdu42 Voir le message
    Cela dit, après pas mal de doc à propos des tâches asynchrones, le .ContinueWith revient à de multiples reprises comme étant de "bas niveau" et qu'il était
    préférable d'utiliser à la place await..
    Si jamais vous avez quelques infos là dessus !
    Le .ContinueWith est tout le temps utilisable, et à partir de la version 4 du framework. Pour async/await, il faut attendre la version 4.5 tout en évitant de l'utiliser avec les méthodes "classiques" comme Task.Wait.

    .ContinueWith permet également une gestion plus fine, en précisant, par exemple, dans quel cas continuer (tout le temps, uniquement en cas d'erreur, uniquement en cas de succès, etc.). De ce point de vue, oui, cette méthode peut être qualifiée de plus bas niveau. Mais c'est vraiment chercher la petite bête !
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  6. #6
    Membre chevronné
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    896
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 896
    Points : 1 912
    Points
    1 912
    Par défaut
    Citation Envoyé par mathisdu42 Voir le message
    Bonjour,

    Merci pour votre réponse, je reviens (un peu tard il est vrai) vers cette discussion pour la mettre à jour.
    J'ai donc pu résoudre la majorité de mes problèmes, en effet ma gestion des Tasks était mal faite, j'ai donc tout revu et migré vers WPF par la même occasion.
    Cela dit, après pas mal de doc à propos des tâches asynchrones, le .ContinueWith revient à de multiples reprises comme étant de "bas niveau" et qu'il était
    préférable d'utiliser à la place await..
    Si jamais vous avez quelques infos là dessus !

    Merci,
    Cordialement.
    Dans les articles de François Dorin tu peux suivre ses tutoriels sur le Pool de Thread.

Discussions similaires

  1. exception dans méthode asynchrone
    Par bobylastar49 dans le forum C#
    Réponses: 6
    Dernier message: 09/01/2013, 15h06
  2. Problème tâches asynchrones
    Par marcaille dans le forum SSIS
    Réponses: 1
    Dernier message: 27/12/2012, 09h49
  3. Tests unitaires - Exceptions multiples
    Par androz dans le forum C#
    Réponses: 6
    Dernier message: 20/12/2011, 23h27
  4. Multiples appels asynchrones et traitements paralleles
    Par zax-tfh dans le forum Windows Communication Foundation
    Réponses: 11
    Dernier message: 27/05/2011, 10h57

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo