web-dev-qa-db-fra.com

Passage d'un paramètre de méthode à l'aide de Task.Factory.StartNew

J'ai le code suivant:

var task = Task.Factory.StartNew(CheckFiles, cancelCheckFile.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);

private void CheckFiles()
{
  //Do stuff
}

Je veux maintenant modifier CheckFiles pour accepter un entier et une référence BlockingCollection

private void CheckFiles(int InputID, BlockingCollection<string> BlockingDataCollection)
{
  //Do stuff
}

Je n'arrive pas à trouver un moyen de démarrer cette tâche comme je l'ai fait ci-dessus.

Pouvez vous aider?

Merci

58
Jon

La meilleure option consiste probablement à utiliser une expression lambda qui se ferme sur les variables que vous souhaitez afficher.

Cependant, soyez prudent dans ce cas, surtout si vous appelez cela en boucle. (Je le mentionne car votre variable est un "ID", ce qui est courant dans cette situation.) Si vous fermez la variable dans la mauvaise portée, vous pouvez obtenir un bogue. Pour plus de détails, voir l'article d'Eric Lippert sur le sujet . Cela nécessite généralement de faire un temporaire:

foreach(int id in myIdsToCheck)
{
    int tempId = id; // Make a temporary here!
    Task.Factory.StartNew( () => CheckFiles(tempId, theBlockingCollection),
         cancelCheckFile.Token, 
         TaskCreationOptions.LongRunning, 
         TaskScheduler.Default);
}

De plus, si votre code ressemble à celui ci-dessus, vous devez utiliser le LongRunning hint avec le planificateur par défaut. Chaque tâche obtiendra son propre thread dédié au lieu d'utiliser le ThreadPool. Si vous créez plusieurs tâches, cela aura probablement un impact négatif car vous n'obtiendrez pas les avantages du ThreadPool. Il est généralement conçu pour une tâche unique et longue (d'où son nom), pas quelque chose qui serait implémenté pour travailler sur un élément d'une collection, etc.

99
Reed Copsey
class Program
{
    static void Main(string[] args)
    {
        Task.Factory.StartNew(() => MyMethod("param value"));
    }

    private static void MyMethod(string p)
    {
        Console.WriteLine(p);
    }
}
19
Fernando Vezzali

Pour passer un seul entier, je suis d’accord avec la réponse de Reed Copsey. Si à l'avenir, vous allez passer des contraintes plus compliquées, j'aime personnellement transmettre toutes mes variables en tant que type anonyme. Cela ressemblera à ceci:

foreach(int id in myIdsToCheck)
{
    Task.Factory.StartNew( (Object obj) => 
        {
           var data = (dynamic)obj;
           CheckFiles(data.id, theBlockingCollection,
               cancelCheckFile.Token, 
               TaskCreationOptions.LongRunning, 
               TaskScheduler.Default);
        }, new { id = id }); // Parameter value
}

Vous pouvez en apprendre plus à ce sujet dans mon blog

6
paulselles

Construisez le premier paramètre sous la forme d'une instance de Action , par exemple.

var inputID = 123;
var col = new BlockingDataCollection();
var task = Task.Factory.StartNew(
    () => CheckFiles(inputID, col),
    cancelCheckFile.Token,
    TaskCreationOptions.LongRunning,
    TaskScheduler.Default);
5
Adam Ralph