Ich habe eine ereignisgesteuerte Anwendung. Ich möchte die Event-Handler (EventHandler
Klasse für viele/alle Ereignisse) eine gemeinsame Implementierung zu halten - während die EventSource
änderbar sein kann (speziell - zur Kompilierzeit).Callback mit niedriger Latenz in C++
Zur Kopplung der EventHandler
mit dem EventSource
, werde ich eine Instanz von Handler im EventSource
speichern müssen. Ich habe versucht, Handler verschiedene Formen zu speichern:
- Zeiger auf eine Schnittstelle von
EventHandler
(die öffentlichen Handler Methoden definierten in BetonEventHandler
‚s - Instanz
std::function
hat - diese bereitgestellt größte Flexibilität
In beiden Fällen war die Latenz beim Aufruf der Zielmethode/Lambda ziemlich hoch (bei meinem Testaufbau ca. 250ns) - und schlimmer noch, war inkonsistent. Kann durch virtuelle Tabellen- und/oder Heap-Zuweisung und/oder sein Typ löschen ???
Um diese Latenz zu reduzieren, möchte ich Vorlagen verwenden.
Das Beste, was ich tun konnte, ist:
template <typename EventHandler>
class EventSource1
{
EventHandler* mHandler;
public:
typedef EventHandler EventHandlerType;
void AssignHandler (EventHandler* handler)
{
this->mHandler = handler;
}
void EventuallyDoCallback (int arbArg)
{
this->mHandler->CallbackFunction (arbArg);
}
};
template <EventSourceType>
class EventSourceTraits
{
typedef EventSourceType::EventHandlerType EventHandlerType;
static void AssignHandler (EventSourceType& source, EventHandlerType* handler)
{
source.AssignHandler(handler);
}
};
class EventHandler
{
public:
void CallbackFunction (int arg)
{
std::cout << "My callback called\n";
}
};
int main()
{
EventSource1<EventHandler> source; /// as one can notice, EventSource's need not to know the event handler objects.
EventHandler handler;
EventSourceTraits<EventSource1>::AssignHandler (source, &handler);
}
Dieses Verfahren eine Beschränkung, dass alle meine EventSource
ist ein Template-Klassen sein.
Frage ist: Ist dies der beste Weg, um konsistente und niedrige Latenz zu erreichen Callback? Kann dieser Code verbessert werden, um zu vermeiden, dass die Ereignisquellklassen völlig unabhängig vom Typ der Ereignishandlerobjekte sind?
Haben Sie ausprobiert, was die Latenz ist, wenn Sie - nur zu Diagnosezwecken - einen bekannten Event-Handler von einer bekannten Ereignisquelle über eine statisch gebundene Funktion aufrufen? Nur um herauszufinden, ob die Latenz tatsächlich durch den Aufruf ausgelöst wird und keine anderen Effekte zutreffen (wie zum Beispiel Objekte, die instanziiert werden sollen, Dispatcher-Code zum Auswerten, Threads, die sich gegenseitig sperren, oder was auch immer)? –
Versuchen Sie zunächst, einen unverschmutzten einfachen Zeiger auf eine reguläre Nichtmitgliedsfunktion zu messen. Kann das nicht übertreffen. Wenn Sie die Leistung akzeptabel finden, haben Sie eine Chance. Ein virtueller Aufruf sollte jedoch im Wesentlichen die gleiche Leistung wie ein Funktionszeiger haben. Hast du wirklich Profiling gemacht? –
@StephanLechner, eine wohlbekannte Elementfunktion eines bekannten Objekts benötigt <30ns konsistent. Ein virtueller Anruf dauert ungefähr 60ns, bleibt aber konsistent. Dies ist entweder akzeptabel (weil sie konsistent sind). Ich bekomme ein ähnliches Verhalten mit dem oben genannten Code mit Vorlage. p.s. Ich habe kein Profiling gemacht. – rat6