Domanda

Ho qualche codice per fare alcune ricerche e contare il verificarsi utilizzando parallel.for:

//...initialize _table with int values...
int elements=60;
int[] outerCounter=new int[elements];
Parallel.For(1, 2000, i0=>
{
  int[] counter=new int[elements];
  int nextPos0=_table[10+i0];
  for(i1=i0+1; i1<1990; i1++){ 
    //...here are also some additionale calculations done...  

    int nextPos1=_table[nextPos0+i1];
    counter[nextPos1]++;
  }
  //synchronize
  for(int i=0; i<elements;i++){
    Interlocked.Add(ref outerCounter[i], counter[i]);
  }
}

Questa versione è il modo più veloce quindi un calcolo sequenziale. Ma mi piacerebbe trovare una soluzione diversa per contare il verificarsi come l'Interocked.Add è un collo di bottiglia. Stavo indagando se PLINQ sarebbe un'opzione, ma non è stato finora in grado di trovare un modo per contare il verificarsi degli elementi nextPos1 in un array.

È stato utile?

Soluzione

mi piacerebbe suggerire fondamentalmente la stessa cosa di Hans, ma ho pensato che sarebbe stato utile fornire qualche codice. Ecco come avrei probabilmente affrontare il problema:

//...initialize _table with int values...
int elements=60;
List<int[]> outerCounter=new List<int[]>();
Parallel.For(1, 2000, i0=>
{
  int[] counter;
  lock(outerCounter)
  {
    if (outerCounter.Count == 0)
      counter = new int[elements];
    else
    {
      counter = outerCounter[outerCounter.Count - 1];
      outerCounter.RemoveAt(outerCounter.Count - 1);
    }
  }
  int nextPos0=_table[10+i0];
  for(i1=i0+1; i1<1990; i1++){ 
    //...here are also some additionale calculations done...  

    int nextPos1=_table[nextPos0+i1];
    counter[nextPos1]++;
  }
  lock (outerCounter)
    outerCounter.Add(counter);
});

int totalCounter = new int[elements];
Parallel.For(0, elements - 1, i =>
{
  foreach (int[] counter in outerCounter)
    totalCounter[i] += counter[i];
});

Altri suggerimenti

Da quello che mi da codice che non si sta per essere in grado di farlo correttamente senza bloccare outcounter [i] dal momento che tutte le discussioni stanno andando a scrivere a tutti i valori in outcounter.

po 'tardi per la festa qui, ma se si sta incrementando solo i valori in contatore [] e outerCounter [], è possibile utilizzare una versione di overload di Parallel.For ()
Invece di creare una matrice locale di elementi di ogni ciclo, è possibile creare un locale alla esecuzione (e sarà gestito solo su di un filo per volta) Ad esempio:

int elements=60;
int[] outerCounter=new int[elements];

Parallel.For (1, 2000,
  () => new int[elements],                        // Initialize the local value.    
  (i0, state, counter) =>
    {
        int nextPos0=_table[10+i0];
        for(i1=i0+1; i1<1990; i1++)
        { 
            //...here are also some additionale calculations done...  
            int nextPos1=_table[nextPos0+i1];
            counter[nextPos1]++;
        }
    }

  counter =>                                    // Add the local value
    { 
        for(int i=0; i<elements;i++)
        {
            Interlocked.Add(ref outerCounter[i], counter[i]);
        }
    }
);

Non ho testato il codice di cui sopra, ma questo è il jist di esso. Esso contribuirà a ridurre drasticamente la quantità di volte che si sta chiamando Interlocked.Add ()

Per ulteriori informazioni, questo sito è molto buona: http://www.albahari.com/threading/part5.aspx

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