71 votes

Est-il un générique Tâche.WaitAll?

Je commence quelques tâches en parallèle, comme ceci:

var tasks =
    Enumerable.Range(1, 500)
    .Select(i => Task.Factory.StartNew<int>(ProduceSomeMagicIntValue))
    .ToArray();

et puis, rejoindre avec

Task.WaitAll(tasks);

Sur cette dernière ligne, je reçois un bleu enchevêtrées marqueur en vertu de l' tasks, avec un message d'avertissement:

Co-variante tableau de conversion de la Tâche[] à la Tâche[] 
peut causer l'exception d'exécution sur l'opération d'écriture.

Je comprends pas pourquoi j'obtiens ce message, mais est-il un moyen de contourner cela? (par exemple, comme une version générique d' Task.WaitAll()?)

34voto

MerickOWA Points 4310

Une méthode générique de la Tâche.WaitAll impliquerait que toutes les Tâches ont pour le retour du même type, qui serait extrêmement faible utilité. D'écrire quelque chose comme cela pourrait être fait manuellement (voir plus Bas Brekelmans de réponse), mais cette habitude de permettre ContinueWith ou d'annulation, sans beaucoup de travail.

Une solution simple, si vous n'êtes pas à l'aide de la matrice pour autre chose est

  .ToArray<Task>();

29voto

DMac the Destroyer Points 1673

Je suis sûr que c'est un fonctionnement sûr, même avec de l'avertissement, mais si vous avez vraiment envie de passer une meilleure option que de créer votre propre mise en œuvre serait juste de convertir votre tasks paramètre dans le type qu'il veut:

Task.WaitAll(tasks.Cast<Task>().ToArray())

Qui tue le bleu gribouillis pour moi, me permet de garder mon tasks variable générique et ne pas me forcer à créer tout un tas de nouvelles effrayant code qui est en fin de compte inutile.

6voto

Bas Brekelmans Points 13799

Vous pouvez créer une extension de la méthode pour ce faire.

Je ne sais pas exactement de la mise en œuvre de WaitAll, mais nous pouvons supposer qu'il attend chaque élément pour compléter:

static class TaskExtensions
{
    public static void WaitAll<T>(this Task<T>[] tasks)
    {
        foreach (var item in tasks)
        {
            item.Wait();
        }
    }
}

Appelez ensuite, à partir de votre code actuel:

tasks.WaitAll();

Modifier

La mise en œuvre réelle est un peu plus complexe. J'ai omis de mentionner le code à partir de cette réponse, car elle est assez longue.

http://pastebin.com/u30PmrdS

Vous pouvez modifier ce à l'appui de tâches génériques.

0voto

denniska86 Points 31
Task.WaitAll(tasks.Cast<Task>().ToArray());

0voto

Un peu plus à l'approche granulaire. Personnellement, j'aime bien la tâche de tableau... juste ma préférence :-)

try
{
    Object sync = new Object();

    CancellationToken token = cts.Token;
    taskArray[i] = Task.Factory.StartNew( () => 
    {
        lock (sync)
        {
            pcq.DoWork(fh);
        }
    }, token);

    bool Completed = Task.WaitAll(taskArray, 60000, token);
    // if still not processed, this row is pretty much not going to happen
    if (Completed == false)
    {

        if (taskArray[i].IsCanceled == false)
        {
            // kill thread
            cts.Cancel();
            // dispose token
            if (cts != null) { cts.Dispose(); }

        }

    }

}
catch (Exception ex)
{}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X