0
votes

Valeur d'argumentation différente de l'intérieur appelé fonction

J'utilise le code ci-dessous pour créer plusieurs tâches dans C #: xxx

Je rencontre un comportement étrange dans le code ci-dessus. En mettant un point d'arrêt à la ligne _tasklist.add (tâche.run ((() => TaskMethod1 (UsalCred))); , je vérifie la valeur de UserCred chaque fois TaskMethod1 est appelé et il n'est pas null tout en étant appelé mais dans l'un des cas, la valeur de userCred est null intérieure TaskMethod1 . Je n'ai aucune idée de la façon dont cela pourrait se produire.


10 commentaires

Je soupçonne que vous avez Problème de variable capturé . Veuillez ajouter du code qui affiche tous les usages de la variable arg1 inside méthode TaskMethod .


Édité avec le code indiquant l'utilisation de la variable à l'intérieur du Taskmethod.


Pouvez-vous s'il vous plaît changer tandis que (cred.tryDequeue (Out UserCred)) {_tasklist.add (tâche.run ((((() => TaskMethod1 (Usalcred))); } à tandis que (cred.tryDequeue (Out UskCred)) {var uc = Usalcred; _tasklist.add (tâche.run ((() => TaskMethod1 (UC))); } et laissez-nous savoir si le problème disparaît?


Est-ce qu'un problème ne se produit que lorsque le débogueur est attaché et disparaît lorsque vous exécutez votre programme avec CTRL + F5 (sans débogage)? Je demande parce que vous avez mentionné un point d'arrêt et que le débogueur n'a pas 100% digne de confiance avec un code multithread.


Savez-vous également que la méthode TaskMethod crée une boucle serrée?


Désolé, @theodorzoulias mais qu'entendez-vous par boucle serrée?


Le trydeffeue retournera FALSE la plupart du temps, le thread continuera de filer non-stop, dans essentiellement un {} boucle.


Oui, il y a des conditions à ne pas laisser cela arriver, j'ai mis. Mais cela ne peut pas la raison du problème que je suis confronté à droite ou peut-être?


Non, c'est certainement sans rapport. Mais je devais le mentionner car il y a des moyens moins chers de produire de la chaleur que d'utiliser des cœurs de cpu filant. :-)


@Enigmativité, il semble avoir travaillé ce que vous avez suggéré, mais je ne suis toujours pas sûr de la raison, pouvez-vous s'il vous plaît expliquer pourquoi cela? (Je suis le stress le test, mais il a passé les tests de base.)


3 Réponses :


1
votes

Vous utilisez la tâche .Run code> où dans vous utilisez des variables à partir de la boucle. Vous n'en passez pas à la tâche. Donc, au moment où la tâche de temps exécute, sa valeur est modifiée.

Vous devez utiliser P>

while (runningService)
{
    string usercred;
    // This will create more than one task in parallel to run,
    // and each task can take upto 30 minutes to finish.
    while (cred.TryDequeue(out usercred))
    {
        _taskList.Add(Task.Factory.StartNew((data) => TaskMethod1(data.ToString()), usercred)
    }
}


1 commentaires

Utilisation de la méthode Task.Factory.StartNew au lieu de Tâche.Run Pour la raison de passer un argument est considéré une technique d'optimisation des performances (évite les fermetures pour les chemins de code sensibles à la performance). Pour le code d'application normal, la tâche .Run est préférable car il est plus lisible.



0
votes

Le changement suivant a résolu le problème.

private static void TaskMethod()
{
    while(runningService)
    {
        string usercred;
        // This will create more than one task in parallel to run,
        // and each task can take up to 30 minutes to finish.
        while(cred.TryDequeue(out usercred))
        {
            var uc = usercred;
            _taskList.Add(Task.Run(() => TaskMethod1(uc)));
        }
    }
}


1 commentaires

La réponse d'une theodor résout le problème. Votre code réutilisait la même référence à userCred donc si la tâche n'a pas démarré assez rapidement le prochain creefreeeue (Out UserCref) écraserait la valeur de UsaterCrred . Qu'est-ce qui a fait null est toujours un mystère pour moi. Mais j'étais curieux si ma suggestion fonctionnerait et cela le faisait.



1
votes

Vous devriez déclarer the userCred code> variable à l'intérieur de l'intérieur pendant code> boucle, de sorte que la Lambda à l'intérieur de la tâche code> Capture une variable distincte pour chaque boucle, et non la même variable pour toutes les boucles.

while(runningService)
{
    while(cred.TryDequeue(out var usercred))
    {
        _taskList.Add(Task.Run(() => TaskMethod1(usercred)));
    }
}


0 commentaires