Question

Je suis nouveau sur C#, Parallel.ForEach, et .NET en général.Je souhaite paralléliser une recherche qui implique des milliers d'emplacements.Pour chaque emplacement, je calcule la distance orthodromique.C'est un calcul que je souhaite étendre à différents cœurs.Ma question est de savoir comment faire si je n'ai que un variable locale du thread, comme dans ceci Exemple MSDN TPL?Pour le résultat, j'ai regardé Interlocked, et j'ai vu ses options Add, CompareExchange, Decrement, Exchange, Increment et Read, mais je ne me contente pas d'ajouter, d'incrémenter, de décrémenter ou de tester l'égalité.Je souhaite renvoyer l'objet, sur plusieurs threads exécutés en parallèle, qui a le plus court dans l'ensemble distance.Mon instinct me dit que cela devrait être facile, que je devrais être capable de créer un petit objet qui enveloppe un Location et une distance, mais comment puis-je capturer la meilleure réponse de chaque fil et alors choisir la distance la plus courte parmi eux ?Voici la version non parallèle :

Location findClosestLocation(Location myLocation, List<Location> allLocations)
{
  double closest = double.MaxValue;
  Location closestLoc = null;
  foreach (Location aLoc in allLocations)
  {
    if (aLoc != myLocation)
    {
      double d = greatCircle(myLocation, aLoc);
      if (d < closest)
      {
        closest = d;
        closestLoc = aLoc;
      }
    }
  }
  return closestLoc;
}

J'ai vu un Article de blog DDJ cela semblait offrir de bons conseils, mais je me demandais si c'était le meilleur conseil.Je vois l'auteur parcourir des tableaux en boucle et je me demande s'il n'existe pas un moyen plus fonctionnel de procéder.Dans le monde fonctionnel, j'utiliserais map, lambda et min.

Était-ce utile?

La solution

L'option la plus simple ici serait de passer à PLINQ :

Location findClosestLocation(Location myLocation, List<Location> allLocations)
{
     return allLocations
               .AsParallel()
               .Min(location => greatCircle(myLocation, location));
}

Cela étant dit, c'est simplement agrégation avec des constructions parallèles.Vous avez plusieurs options si vous souhaitez vous en tenir à la classe Parallel.Une option serait de synchroniser cela vous-même au sein du bloc, en utilisant le verrouillage.Je ne le recommanderais pas, car cela nuirait à vos performances globales.

La meilleure option est d'utiliser le Parallèle.ForEach méthodes qui prévoient l'État local.Ils vous permettraient de réécrire ceci comme :

Location findClosestLocation(Location myLocation, List<Location> allLocations)
{
  double closest = double.MaxValue;
  Location closestLoc = null;
  object sync = new object();

  Parallel.ForEach<Location, Tuple<double,Location>(
      allLocations,
      () => new Tuple(double.MaxValue, null),
      (location, loopState, localState) =>
      {
          double d = greatCircle(myLocation, aLoc);
          if (d < localState.Item1)
              return new Tuple(d, aLoc);
          else
              return localState;
      },
      localState =>
      {
          lock(sync)
          {
              if (localState.Item1 < closest)
              {
                  closest = localState.Item1;
                  closestLoc = localState.Item2;
              }
          }
      }
  );
  return closestLoc;
}

Je couvre en utilisant état local pour les agrégations en détail sur mon blog.Cela modifie fondamentalement l'opération en une opération de verrouillage par thread au lieu d'un verrou par élément de traitement, de sorte que vous obtenez un débit beaucoup plus élevé qu'une solution de verrouillage naïve.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top