2013-12-18 12 views
5

Korzystam z czyjegoś kodu źródłowego hydrodynamiki cząstek otwartych .NET 4 o otwartym kodzie źródłowym i próbuję przekonwertować go na projekt Unity, na który można tylko liczyć, aby być .NET 2 standardy. Niestety kod używa klasy Parallels (co jest niesamowite!), Ale użył jednego z bardziej niejasnych przeciążeń. Czy każdy może zobaczyć dobry sposób na osiągnięcie tego samego w .NET 2 bez ogromnego uderzenia wydajności?Konwertowanie .NET 4 Gwintowanie do .NET 2

Parallel.For(
     0, 
     _numActiveParticles, 
     () => new Vector2[MAX_PARTICLES], 
     (i, state, accumulatedDelta) => calculateForce(_activeParticles[i], accumulatedDelta), 
     (accumulatedDelta) => 
     { 
      lock (_calculateForcesLock) 
      { 
       for (int i = _numActiveParticles - 1; i >= 0; i--) 
       { 
        int index = _activeParticles[i]; 
        _delta[index] += accumulatedDelta[index]/MULTIPLIER; 
       } 
      } 
     } 
    ); 

myślę to co robi kod (bez gwintowanych):

for (int i = 0; i < _numActiveParticles; i++) 
    { 
     Vector2[] temp = new Vector2[MAX_PARTICLES]; 
     temp = calculateForce(_activeParticles[i], temp); 


     for (int k = _numActiveParticles - 1; k >= 0; k--) 
     { 
      int index = _activeParticles[k]; 
      _delta[index] += temp[index]/MULTIPLIER; 
     } 
    } 
+2

Może się okazać się pomocne http://stackoverflow.com/q/12386686/809009 –

+0

@OndrejJanacek Thanks to pomocne, ale nie jestem też w 100% pewna, co robi wersja Parallels, więc chcę się upewnić, że poprawnie ją przetłumaczę. – PorcupineRending

+0

Nie sądzę, że twoje zrozumienie jest właściwe. W ogóle nie używasz zmiennej "temp". Przeczytaj to: http://msdn.microsoft.com/en-us/library/ff963547.aspx –

Odpowiedz

1

Twój drugi kod nie jest poprawny. Myślę, że poprawny kod jest tak:

var accumulatedDelta= new Vector2[MAX_PARTICLES]; 

for(int i = 0; i < _numActiveParticles; ++i) 
{ 
    accumulatedDelta = calculateForce(_activeParticles[i], accumulatedDelta); 
} 

for (int i = _numActiveParticles - 1; i >= 0; i--) 
{ 
    int index = _activeParticles[i]; 
    _delta[index] += accumulatedDelta[index]/MULTIPLIER; 
} 

nie wiem co .net2 ma, a co nie. Ale możesz samemu symulować Parallel.For.

wyjaśnienie tego przeciążenia Parallel.For to:

Pierwszy parametr: start indeks pętli

Drugi parametr: indeks koniec pętli

Trzeci parametr: delegat, który utworzy zadanie dane lokalne . dla każdego wątku, którego używa Parallel.For (zadanie), ten uczestnik zostanie wywołany i zwróci dane localInit.

Czwarty parametr: delegat, który działa jak ciało o numerze for. Przy pierwszym uruchomieniu delegata treści ten delegat pobierze dane utworzone przez wcześniejszego delegata (localInit). w każdej kolejnej pętli delegat ciała może zmienić localInit, a następnie powrócić do następnej realizacji. W ostatnim wykonaniu delegacji ciała, dane będą przekazywane do ostatniego delegata.

Ostatni parametr: inny uczestnik, który zostanie wywołany za każde zadanie, gdy zadanie zakończyło pracę. localInit zostanie przekazany temu delegatowi. Ponieważ ten delegat może być nazywany współbieżnością przez wiele zadań, musisz chronić swoje udostępniane dane.

Edit:

Wersja ParallelFor może być tak:

public static void ParallerFor<TLocal>(int startIndex, int endIndex, Func<TLocal> initData, Func<int, TLocal, TLocal> body, Action<TLocal> finalizer) 
    { 
     int numThreads = Environment.ProcessorCount; 
     int chunkOffset = ((endIndex - startIndex)/numThreads) + 1; 

     Task[] tasks = new Task[numThreads]; 

     Enumerable.Range(0, numThreads).ToList().ForEach(x => 
      { 
       int start = x * chunkOffset; 
       int end = ((x + 1) * chunkOffset); 
       end = end > endIndex ? endIndex : end; 

       tasks[x] = Task.Factory.StartNew(() => 
       { 
        TLocal init = initData(); 

        for(int i = start; i < end; ++i) 
        { 
         init = body(i, init); 
        } 

        finalizer(init); 
       }); 
      }); 

     Task.WhenAll(tasks).Wait(); 
    } 
+0

Używanie klasy Zadanie do ponownego uzupełnienia Równolegle. Dla własnego nastroju. Jeśli masz jedną, masz również drugą (obie są .net 4 i wyżej). –

+0

@ Christian.K Dziękuję za wzmiankę. Nie wiem, jakiego rodzaju pomocników równoległych '.net 2' ma, ale zastąpienie' task' z ręcznym 'thread' starting jest prostą pracą. – MRB

+0

Możesz sprawdzić msdn. To ci powie. Zauważ, że zadanie nie jest takie samo jak wątek (przynajmniej użyj puli wątków, a nie zwykłego wątku). Ogólnie rzecz biorąc, ponowne wprowadzenie funkcjonalności TPL nie jest trywialne, aby uzyskać poprawność i wydajność. Wiele materiałów na ten temat w Internecie. –