5

J'ai un List<byte[]> et j'aime désérialiser chaque byte[] dans Foo. La liste est ordonnée et j'aime écrire une boucle parallèle dans laquelle le résultat List<Foo> contient tous les Foo dans le même ordre que l'original byte[]. La liste est considérablement grande pour rendre l'exploitation parallèle utile. Existe-t-il un moyen intégré d'accomplir cela?Parallel.ForEach tout en conservant l'ordre

Si ce n'est pas le cas, des idées sur la façon d'accélérer le fonctionnement de tout ceci de manière synchrone?

Merci

+0

après un certain code d'échantillon et s'il vous plaît pour le dossier qui rend les choses ne marche pas nécessairement parallèle rendent plus rapide et efficace ... Je me demande si Parallel.For résoudrait votre problème. Ce – adt

+3

est un double de celle-ci: http://stackoverflow.com/questions/3639768/parallel-foreach-ordered-execution Pour répondre, vous pouvez utiliser PLINQ (AsOrdered, AsParallel) pour faire le travail. – Kadelka

+0

Il vaudrait mieux avoir l'équivalent parallèle de 'Select' ou' Map' pour conserver l'ordre d'entrée. – leppie

Répondre

4

De l'information que vous » Vraiment donné, je comprends que vous voulez avoir un tableau de sortie de Foo avec une taille égale au tableau d'entrée d'octets? Est-ce correct?

Si oui, oui l'opération est simple. Ne vous embêtez pas avec des constructions verrouillées ou synchronisées, celles-ci vont éroder toute la vitesse que vous donne la parallélisation.

Au lieu de cela, si vous obéissez cette règle simple tout algorithme peut être parallélisés sans verrouillage ou synchronisation:

Pour chaque élément d'entrée X [i] traitée, vous pouvez lire à partir de tout élément d'entrée X [j], mais seulement écrire à l'élément de sortie Y [i]

enter image description here

Consulter/regroupement, ce type d'opération est appelé un seul Rassemblez élément de sortie est écrite.

Si vous pouvez utiliser le principe ci-dessus, vous voulez créer votre tableau de sortie Foo [] à l'avant, et utiliser Parallel.For ForEach sur le tableau d'entrée.

E.g.

 List<byte[]> inputArray = new List<byte[]>(); 
     int[] outputArray = new int[inputArray.Count]; 

     var waitHandle = new ManualResetEvent(false); 
     int counter = 0; 

     Parallel.For(0, inputArray.Count, index => 
      { 
       // Pass index to for loop, do long running operation 
       // on input items 
       // writing to only a single output item 
       outputArray[index] = DoOperation(inputArray[index]); 

       if(Interlocked.Increment(ref counter) == inputArray.Count -1) 
       { 
        waitHandle.Set(); 
       } 
      }); 

     waitHandler.WaitOne(); 

     // Optional conversion back to list if you wanted this 
     var outputList = outputArray.ToList(); 
+0

Marqué votre réponse comme solution souhaitée, mais à la fin, je suis allé avec un IPropagatorBlock personnalisé et TPLDataflow grâce à l'aide de svick. Bien que les deux, cette question et le flux de données semblent deux concepts très différents à la surface, le traitement parallèle des blocs de données dans l'IPropagatorBlock largement surpassé toute boucle Parallel.For en ce qui concerne mon problème spécifique. J'ai trouvé que la surcharge de synchronisation de la notification de mappage et d'achèvement est très coûteuse et que TPL Dataflow cible des scénarios tels que le mien. Mais cela ne réduit en rien votre solution à ma question spécifique ... –

+0

... qui n'incluait pas le problème de la synchronisation et de la notification d'achèvement. Il s'agissait de Parallel.Foreach tout en conservant l'ordre et votre solution proposée correspond à la facture. Merci beaucoup. –

+0

Bon point! Task parallèle bibliothèque est une solution supérieure. Je suis surpris qu'il surpasse quand même. Peut-être sa limitation de la tâche d'exécuter plus d'une sérialisation par thread? Pour ce qui précède, vous pouvez inclure une notification complète avec un compteur d'entiers et 'Interlocked.Increment (ref counter)' pour tester si tous les éléments ont été traités. Puis définissez un waithandle pour continuer. –

2

Vous pouvez utiliser un dictionnaire threadsafe avec une clé int index pour stocker le reult de foo donc à la fin, vous aurez tout le donneur d'ordre de données dans le dictionnaire

+0

Merci, je suis conscient de cela, mais cela semble terriblement compliqué. J'ai fondamentalement besoin d'une autre procédure complète pour attendre le prochain Foo entrant suivant dans l'ordre, vérifier la synchronicité, et ajouter des éléments dans le bon ordre dans la liste résultante. On dirait un peu de frais généraux qui peut vaincre toute la notion de courir en parallèle. –

Questions connexes