49 votes

Utilisation des instructions AsParallel () / Parellel.ForEach ()?

La recherche d'un peu de conseils sur l'effet de levier AsParallel() ou Parallel.ForEach() à la vitesse de cette.

Voir la méthode que j'ai (simplifié/métisser pour cet exemple) ci-dessous.

Il faut une liste comme "US, FR, APAC", où "APAC" est un alias de peut-être 50 autres "US, FR, JP, C', GO", etc. pays. La méthode "US, FR, APAC", et de le convertir à une liste de "NOUS", "FR", en plus de tous les pays qui sont dans "APAC".

private IEnumerable<string> Countries (string[] countriesAndAliases)
{
    var countries = new List<string>();

    foreach (var countryOrAlias in countriesAndAliases)
    {
        if (IsCountryNotAlias(countryOrAlias))
        {
            countries.Add(countryOrAlias);
        }
        else 
        {
            foreach (var aliasCountry in AliasCountryLists[countryOrAlias]) 
            {
                countries.Add(aliasCountry);
            }
        }
    }

    return countries.Distinct();
}

Ce parallélisée aussi simple que de changer à ce qui est ci-dessous? Il y a plus de nuance à l'aide d' AsParallel() que cela? Dois-je utiliser Parallel.ForEach() au lieu de foreach? Quelles sont les règles du pouce doit-je utiliser lors de la parallélisation foreach boucles?

private IEnumerable<string> Countries (string[] countriesAndAliases)
{
    var countries = new List<string>();

    foreach (var countryOrAlias in countriesAndAliases.AsParallel())
    {
        if (IsCountryNotAlias(countryOrAlias))
        {
            countries.Add(countryOrAlias);
        }
        else 
        {
            foreach (var aliasCountry in AliasCountryLists[countryOrAlias].AsParallel()) 
            {
                countries.Add(aliasCountry);
            }
        }
    }

    return countries.Distinct();
}

74voto

Andrey Points 36869

Plusieurs points.

l'écriture countriesAndAliases.AsParallel() est inutile. AsParallel() fait partie de la requête Linq qui vient après qu'il l'exécuter en parallèle. Le cadre est vide, donc pas de l'utiliser à tout.

généralement, vous devriez repace foreach avec Parallel.ForEach(). Mais attention de ne pas thread-safe code! Vous l'avez. Vous ne pouvez pas simplement conclure en foreach car List<T>.Add n'est pas thread-safe elle-même.

donc, vous devriez faire comme ceci (désolé, je n'ai pas fait de test, mais il compile):

        return countriesAndAliases
            .AsParallel()
            .SelectMany(s => 
                IsCountryNotAlias(s)
                    ? Enumerable.Repeat(s,1)
                    : AliasCountryLists[s]
                ).Distinct();

Edit:

Vous devez être sûr de deux choses:

  1. IsCountryNotAlias doit être thread-safe. Il serait encore mieux si c'est de la pure fonction.
  2. Nul ne modifiera AliasCountryLists entre-temps, parce que les dictionnaires ne sont pas thread-safe. Ou utiliser ConcurrentDictionary pour être sûr.

Liens utiles qui vous aideront à:

Les modèles de Programmation Parallèle: la Compréhension et l'Application de Modèles Parallèles avec la .NET Framework 4

La Programmation parallèle dans .NET 4 des Directives de Codage

Quand Dois-Je Utiliser En Parallèle.ForEach? Quand Devrais-je Utiliser PLINQ?

PS: Comme vous le voyez de nouvelles parallèle fonctionnalités ne sont pas aussi évidente qu'ils regardent et se sentent à l').

14voto

Reed Copsey Points 315315

Lors de l'utilisation de AsParallel(), vous devez vous assurer que votre corps est thread-safe. Malheureusement, le code ci-dessus ne fonctionnera pas. List<T> n'est pas thread-safe, de sorte que votre plus de AsParallel() sera la cause d'une condition de course.

Si, toutefois, vous passez vos collections à l'aide d'une collection dans le Système.Les Collections.Simultanées, comme ConcurrentBag<T>, le code ci-dessus sera plus susceptible de travailler.

3voto

cjg Points 1935

Je préférerais utiliser une autre structure de données, telle qu'un ensemble pour chaque alias, puis utiliser union pour les fusionner.

Quelque chose comme ça

 public string[] ExpandAliases(string[] countries){
    // Alias definitions
    var apac = new HashSet<string> { "US", "FR", ...};
    ... 

    var aliases = new HashMap<string, Set<string>> { {"APAC": apac}, ... };

    var expanded = new HashSet<string>
    foreach(var country in countries){
        if(aliases.Contains(country)
            expanded.Union(aliases[country]);
        else{
            expanded.Add(country);
    }

    return expanded.ToArray();
}
 

Remarque: le code doit être considéré comme un pseudo-code.

1voto

Steve M Points 4137

Cela me semble être une opération en série par nature. Tout ce que vous faites est de parcourir une liste de chaînes et de les insérer dans une autre liste. Les bibliothèques de parallélisation vont faire cela, plus un tas de threads et de synchronisation - cela finirait probablement plus lentement.

En outre, vous devriez utiliser HashSet<string> si vous ne voulez pas de doublons.

0voto

BlueCode Points 581

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