Hy@everybody,
ich arbeite schon seit ca. einem Jahr an einem RayTracer (kein 0815 Tracer für Spiele, sonder ein physikalisch absolut korrekter Tracer).
Ich habe zwei Konfigurationseinstellungen für die Assemblies. Einmal "SingleCore" und einmal "MultiCore". Die Funktionen (und deren Geschwindigkeit) des Tracers werden im SingleCore - Modus geschrieben/geprüft. Im MultiCore versuche ich diese zu Parallelisieren.
Mein Problem ist folgendes: Ich schaffe es nicht die einzelnen Kerne zu 100% zu belasten (dass das nicht exakt möglich ist ist mir schon klar 😃 ). Jeder Kern (auf meiner Maschine 4 Kerne) werden nur zu ca. 60% ausgelastet. Nun habe ich den Effekt, das meine SingleCore-Variante fast doppelt so schnell ist wie die MultiCore-Variante und für mich ist das ein großes Rätsel. Ich habe schon einige Sachen ausprobiert, es hat aber leider nicht zu einem wirklichen Erfolg geführt.
Meine erste Vermutung war, das die Threads zu schlecht ausgelastet sind, somit habe ich einem Thread mehrere Strahlen gegeben => Änderung 0
Ich habe die schreibenden Zugriffe (die Sensoren) auskommentiert => Änderung 0
Für mich ist das echt ein Rätsel. Hier eine kurze Erklärung meines Programms:
Aus einem sehr bekannten CAD-System werden Geometrieobjekte in Dreiecke konvertiert (gemesht) und in eine XML-Datei geschrieben. Diese Datei wird dann von meinem Tracer eingelesen und in einem großen Objekt (class Scene3D) gehalten. Im Scenen-Objekt ist auch ein spezieller Strahlengenerator, der aus Dateien Strahldaten einliest und dem Tracer zu Verfügung stellt. Jeder einzelne Strahl wird in die Scene geschickt und getract. Sollte ein Strahl einen Sensor treffen, so wird die logischerweise gespeichert.
So, hier nun meine zwei Code-Variante:
-) SingleCore
this.traceInfo.Multithreading = false;
TraceInfo localInfo = this.traceInfo;// trace-information, ob z.B. manche Strahlgänge nicht berechenbar sind
for (Int32 k = 0; k < CountOfRaysForIteration; k++)
{
if (IsCancel)// abfrage für cancel
{
break;
}
RayCalculation ray = null;
this.Scene.Source.GetRay(k, ref ray);// von der Scene wird der zu berechnende Strahl ermmittelt
ActualRayCount += ray.RepeatTime;//wieviele rays sind bis jetzt simuliert worden
TraceRay(ray, RefractionIndexEnvironment, AbsorptionCoefficientEnvironment, ref localInfo,bw);//die Hauptfunktion, hier wird ein Strahl in die Scene geschickt und verfolgt (trace)
if (ActualRayCount % RayCountEventTick == 0)//alle n Strahlen wird ein Event für den Fortschrittsbalken ausgelöst
{
OnRayCountTick(new RayCountEventArgs(ActualRayCount));
}
}
-) MultiCore
this.traceInfo.Multithreading = true;
Object localobj = new object();
try
{
//for (Int32 k = 0; k < CountOfRaysForIteration; k++)
Parallel.For<TraceInfo>(0, CountOfRaysForIteration, () => new TraceInfo(), (k, loop, localstate) =>
{
#if DEBUG
FileStream fss = null;
#endif
BinaryWriter bww = null;
try
{
if (IsCancel)
{
loop.Break();
}
#if DEBUG
fss = new FileStream(Scene.OutputDirectory + Scene.SimulationParameters.SimulationName + ".lef", FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write);
bww = new BinaryWriter(fss);
#endif
////
RayCalculation ray = null;
this.Scene.Source.GetRay((int)k, ref ray);
lock (localobj) { ActualRayCount += ray.RepeatTime; }
TraceRay(ray, RefractionIndexEnvironment, AbsorptionCoefficientEnvironment, ref localstate, bww);
if (ActualRayCount % RayCountEventTick == 0)
{
OnRayCountTick(new RayCountEventArgs(ActualRayCount));
}
}
catch (Exception ex)
{
throw ex;
}
#if DEBUG
finally
{
if (bww != null)
{
bww.Close();
bww = null;
}
if (fss != null)
{
fss.Close();
fss = null;
}
}
#endif
return localstate;
},
(localstate) => { lock (localobj) { traceInfo += localstate; } }
);
}
catch (AggregateException ex)
{
String Text = "";
foreach (Exception e in ex.InnerExceptions)
{
Text += e.Message + "\n";
}
throw new Exception(Text);
}
Hatte jemand schon mal ähnliche Probleme?
MfG
Tonka