Die meisten effizienten Art und Weise zu verarbeiten, die ein queue mit threads
Habe ich eine queue auf, die ausstehende fourier-Transformation-Anforderungen (vergleichsweise zeitaufwändige Operationen) platziert sind - wir könnten Tausende von transform-Anforderungen pro Sekunde in einigen Fällen so sein musst schnell sein.
Ich bin die Erneuerung der alten code zu verwenden .net 4, sowie die Portierung von TPL. Ich Frage mich, was die effektivsten (schnellsten Durchsatz) Weg, dies zu behandeln Warteschlange aussieht. Ich möchte die alle verfügbaren Kerne.
Derzeit bin ich Experimentieren mit einer BlockingCollection. Ich erstelle ein queue handler-Klasse, die spawns 4 Aufgaben, die block auf der BlockingCollection und warten auf die eingehenden arbeiten. Sie dann verarbeiten, die anstehende Transformation. Code:
public class IncomingPacketQueue : IDisposable
{
BlockingCollection<IncomingPacket> _packetQ = new BlockingCollection<IncomingPacket>();
public IncomingPacketQueue(int workerCount)
{
for (int i = 0; i < workerCount; i++)
{
Task.Factory.StartNew(Consume);
}
}
public void EnqueueSweep(IncomingPacket incoming)
{
_packetQ.Add(incoming);
}
private void Consume()
{
foreach (var sweep in _packetQ.GetConsumingEnumerable())
{
//do stuff
var worker = new IfftWorker();
Trace.WriteLine(" Thread {0} picking up a pending ifft".With(Thread.CurrentThread.ManagedThreadId));
worker.DoIfft(sweep);
}
}
public int QueueCount
{
get
{
return _packetQ.Count;
}
}
#region IDisposable Members
public void Dispose()
{
_packetQ.CompleteAdding();
}
#endregion
}
Sieht das aus wie eine gute Lösung? Es scheint, max, alle Kerne - obwohl ich bin mir derzeit nicht sicher, wie viele Arbeiter sollte ich spawn in meiner Konstruktor.
- On a side note, Sie können auch die Intel IPP zur Beschleunigung der Fourier-transform-Arbeit (jeder thread läuft auf einem core wird dann die Nutzung der SSE-Anweisungen, die die Arbeit machen), aber dann haben Sie das Vergnügen interop 😉
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sieht zumutbar ist. Ich habe festgestellt
BlockingCollection
ganz schnell. Ich benutze es zum Prozess Zehntausende Anfragen pro Sekunde.Wenn Ihr Antrag Prozessor gebunden, dann haben Sie wahrscheinlich nicht wollen, zu schaffen und mehr Arbeitskräfte haben, als Sie Kerne. Sicherlich wollen Sie nicht erstellen viel mehr Arbeitnehmer als Kerne. Auf einem quad-core-Maschine, wenn Sie erwarten, die meiste Zeit damit verbracht, die FFTs, dann vier Arbeiter Essen die CPU. Mehr Arbeiter bedeutet nur mehr, dass Sie thread-Kontext-switches zu behandeln. Die TPL wird in der Regel balance, die für Sie, aber es gibt keinen Grund, zu erstellen, zu sagen, 100 Arbeitnehmern, wenn Sie nicht umgehen kann mehr als eine Handvoll.
Ich würde vorschlagen, dass Sie tests ausführen, mit 3, 4, 5, 6, 7, und 8 Arbeiter. Sehen, die man bietet Ihnen den besten Durchsatz.
Ich Stimme mit Jim. Dein Ansatz sieht wirklich gut aus. Sie werden nicht erhalten viel besser diese. Ich bin nicht ein FFT-Experte, aber ich gehe davon aus, dass diese Operationen werden fast 100% CPU-gebunden. Wenn das tatsächlich der Fall ist, dann eine gute erste Vermutung bei der Anzahl von Arbeitnehmern wäre eine direkte 1-zu-1 Korrelation mit der Anzahl der cores in der Maschine. Sie können
Environment.ProcessorCount
um diesen Wert. Sie könnte Versuch mit einem Multiplikator von sagen 2x oder 4x, aber wieder, wenn diese Operationen sind CPU-gebunden dann etwas höher als 1x möglicherweise nur mehr Aufwand. MitEnvironment.ProcessorCount
würde Ihren code portabler.Anderen Vorschlag...lassen Sie die TPL wissen, dass diese dedizierte threads. Sie können dies tun, indem Sie angeben, die
LongRunning
option.Warum nicht Parallel.ForEach und lassen TPL Griff der Anzahl der erstellten threads.
(die GetConsumingPartitioner ist Teil der ParallelExtensionsExtras)
Stellen Sie die Anzahl der Arbeitnehmer configruable. Auch zu viele Arbeiter und zu wird es langsamer (angezeigt durch ein weiteres Plakat), so müssen Sie den sweet spot. Ein konfigurierbarer Wert erlauben würde Testläufe zu finden, der optimale Wert oder erlauben würde, Ihr Programm anpassungsfähig für verschiedene Arten von hardware. Man könnte sicherlich platzieren Sie diesen Wert in der App.Config und Lesen Sie es auf startup.
Könnte man auch versuchen, mit PLINQ zu parallelisieren, die Verarbeitung, um zu sehen, wie es im Vergleich zu dem Ansatz, den Sie gerade verwenden. Es hat einige tricks in petto, die es sehr effizient, unter bestimmten Umständen.