Domanda

Sono nuovo a C #, Parallel.ForEach e .Net in generale. Voglio parallelizzare una ricerca che coinvolga migliaia di luoghi. Per ogni posizione, calco la grande distanza del cerchio. Questo è un calcolo che voglio diffondersi a diversi core. La mia domanda è come faccio a farlo se ho solo una variabile locale -thread-locale, come in questo MSDN TPL Esempio ? Per il risultato, ho guardato Interlocked, e ho visto le sue opzioni Add, CompareExchange, Decrement, Exchange, Increment e Read, ma non sto solo aggiungendo, incrementando, decrementazione o test per l'uguaglianza. Voglio restituire l'oggetto, su diversi fili in esecuzione in parallelo, che ha la distanza più breve complessiva . Il mio Gut dice che questo dovrebbe essere facile, che dovrei essere in grado di creare un po 'di oggetto che avvolge un Location e una distanza, ma come faccio a catturare la risposta migliore da ogni thread e allora scegli la distanza più breve tra loro? Ecco la versione non parallela:

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;
}
.

Ho visto un DDJ Blog Post che sembrava Offri un buon consiglio, ma mi chiedevo se fosse il miglior consiglio. Vedo l'autore che looping su array e mi chiedo se non c'è un modo più funzionale di farlo. Nel mondo funzionale utilizzerei map, lambda e min.

È stato utile?

Soluzione

L'opzione più semplice qui sarebbe passare a Plinq:

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


.

Detto questo, questo è fondamentalmente solo Aggregazione con costrutti paralleli . Hai un paio di opzioni se vuoi attenersi alla classe parallela. Un'opzione sarebbe quella di sincronizzarsi con te stesso all'interno del blocco, utilizzando il blocco. Non lo consiglierei, in quanto danneggerà la tua performance generale.

L'opzione migliore è utilizzare il Parallel.Fodeah Metodi che prevedere lo stato locale. Ti permetteranno di riscrivere questo come:

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;
}
.

Io coprio usando Stato locale per aggregazioni in dettaglio sul mio blog . Ciò cambia fondamentalmente l'operazione a un'operazione di blocco per filo anziché un blocco per elemento di elaborazione, in modo da ottenere un throughput molto più alto rispetto a una soluzione di blocco ingenua.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top