Twisted

  •  

    Reactor Pattern

    Um was gehts

    Das Reaktor Pattern erlaubt es, einer ereignis-getriebenen Anwendung eine oder mehrere Client Anfragen gleichzeitig anzunehmen und auf verschiedene Serviceanbieter zu verteilen ( demultiplex and dispatch ) .

    Auch bekannt unter

    • Dispatcher
    • Notifier

    Beispiel

    • Ein Logging Server erhält mehrere Anfragen gleichzeitig und muß sie auf die verschieden Ausgabegeräte verteilen:
      NetworkLogging.gif
    • Eventhandling ins GUIs

    Anforderungen

    Ein Server soll mehrere Clientanfragen gleichzeitig beantworten können. Jede Clientanfrage besitzt eine eindeutige Indikation, die sie einem Serviceprovider zuordnen läßt. Folgende Bedingungen müssen für die Applikation gewährleistet sein:
    • sie soll nicht blockieren
    • sie soll auf maximalen Durchsatz ausgelegt sein und somit unnötiges Kontext wechseln, Daten synchronisieren oder Daten kopieren vermeiden
    • sie soll einfach um neue und verbesserte Service erweitert werden können
    • sie soll ohne komplexe multithreading und synchronisations Mechanismen auskommen

    Lösung

    Führe für jeden Servicetyp, den die Applikation anbietet, einen Handler ein. Dieser Eventhandler verarbeitet die spezifische Clientanfragen. Registriere den Handler beim Reaktor, der einem synchronen Event Verteiler (event demultiplexer) unterhält um auf eingehende Events zu reagieren. Wenn ein Event im synchronen event demultiplexerauftritt, benachrichtigt dieser den Reaktor, der das Event auf den angefragen Service verteilt.

    Struktur

    Handles

    • identifizieren Eventquellen wie Sockets, Filehandles oder Timersignale des OS-Systems
    • die Eventquellen erzeugen Events wie connect, read, time-out an, die auf den assoziierten Handle geschoben werden
    • der Handle kann nur die entsprechende Operation vollziehen

    synchrone event demultiplex

    • der Verteiler (demultiplexer) wartet auf Indikatoren (indication events), die auf einer Menge von Handles auftreten
    • bis die indication events abgeholt werden, blockiert der event _demultiplexer
    • auf dem assozierten Handle kann nun das eintreffende Ereignis aufgerufen

    Event Handler

    • definiert das Interface um indication events zu prozessieren
    • deklarieren die Services der Applikation

    Konkrete Event Handler

    • verarbeiten indication events in einer applikationsspezifischen Art
    • definieren die Services der Applikation

    Reaktor

    • stellt ein Interface zu Verfügung, damit die Event Handler inklusiver ihrer assozierten Handles registrieren und entfernen kann
    • der Reaktor benützt den synchronen Verteiler (event demultiplexer) um auf die Indikatoren (indicaton events) der Handles zu warten
    • beim Auftreten eines Indikators (indication events) ordnet der Reaktor dies Ereugnis dem entsprechenden Ereignis Handler zu
    • nach der Zuordnung des Ereignis an den entsprechenden Ereignis Handler, ruft ( dispatch ) der Reaktor die assozierte Methode auf dem Event Handler auf
    • der Reaktor startet und unterhält die event loop der Applikation
    Nicht die Applikation, sonder der Reaktor wartet auf indication events, die er auf die entsprechenden konkreten Event Handler verteilt ( demultiplex ) und dann deren assozierte Hook Methode aufruft ( dispatch ). Als Applikationsentwickler gilt es die spezifischen Event Handler zu implementieren und sie beim Reaktor zu registrieren.
    Der Reaktor als Framework stellt eine Ablaufumgebung für die Eventverarbeitung bereit. Diese inversion of control - die Applikation wird durch den Reaktor gesteurt - wird als Hollywood Prinzip bezeichnet.
    Don't call me, we call you.

    • Reaktor Klassendiagramm:
      reactorClassDiagram.gif

     

    Umsetzung

    Timer mit twisted

    Der Reaktor reagiert auf Zeittakte. Diese Ereignisse werden auf die registrierten Handler abgebildet. Sobald die Eventloop des Reaktors mittels reactor.run() gestartet wird, können die Ereignisse verarbeitet werden.
    import time

    from twisted.internet import task
    # http://twistedmatrix.com/trac/browser/trunk/twisted/internet/task.py
    from twisted.internet import reactor

    # http://twistedmatrix.com/trac/browser/trunk/twisted/internet/reactor.py

    # define handler as object
    class Handler():

    def __init__(self, Id ):

    self.__id= Id

    def __call__(self):

    print "Handler with id %s" % self.__id
    print "at %d:%d:%d%s\n" %(time.localtime()[3:6] + ( str(time.time() % 1)[1:] ,))


    # register handler as callable object
    l1 = task.LoopingCall(Handler(1))
    # start the task

    # start calls implicit reactor.callLater(... ) to reschedule the task ( fire the time event )
    l1.start(0.3) # call every 0.3 seconds

    l2 = task.LoopingCall(Handler(2))

    l2.start(1) # call every second

    # running the event loop
    reactor.run()

    Timer mit ACE

    • starte zwei Timer cb1 und cb2, die durch Signale SIGTSTP und SIGINT um den Faktor 10 abgebremst werden können
    Die ACE Variante ist deutlicher verboser, da hier auf Time- und Signalevents mit den entsprechenden CB und Signalhandler reagiert wird. Insbsondere sorgt der TimerDispatcher für das explizite Feueren der Timeevents.
    Durch die schedule Methode des Timers bzw. die register_handler des Reactors werden die Handler registriert. Während der CB Handler auf Timeevents mit handle_timeout reagiert, reagiert der Signalhandler auf Signalevents mit handle_signal. Beide Eventhandler werden durch die gleichen Verteiler bedient ( select ). Die ACE_Timer_Queue bzw. der konkrete Implementierung ACE_Timer_Heap merkt sich die die zukünftigen Zeitpunkte, zu denen sie expire an den Verteiler schickt.
    Die Methode wait_for_event startet die Eventloop, die dann auf die Timer- und Signalevents reagiert.
    #include "ace/Timer_Queue.h"
    #include "ace/Timer_Heap.h"
    #include "ace/Reactor.h"
    #include "CB.h"

    #include "SignalHandler.h"
    #include "TimerDispatcher.h"

    int main()
    {

    CB cb1, cb2;
    cb1.setID(1);
    cb2.setID(2);

    int arg1 = 1, arg2 = 2;

    ACE_Timer_Queue *timer_queue;

    ACE_NEW_RETURN(timer_queue, ACE_Timer_Heap, -1);

    // setup the timer queue

    Timer::instance()->set(timer_queue);

    ACE_Time_Value curr_time = ACE_OS::gettimeofday();

    ACE_Time_Value threeSeconds = curr_time + ACE_Time_Value(3L);
    ACE_Time_Value fourSeconds = curr_time + ACE_Time_Value(4L);

    // start in 3 seconds, each second
    long timerId1= Timer::instance()->schedule(&cb1, &arg1, threeSeconds, ACE_Time_Value(1));

    // start in 4 seconds; each 0.3 secondcs
    long timerId2=Timer::instance()->schedule(&cb2, &arg2, fourSeconds, ACE_Time_Value(0,300000));


    // Strg c
    SignalHandler *mutateTimer1= new SignalHandler( timerId1 );

    // Strg z
    SignalHandler *mutateTimer2= new SignalHandler( timerId2 );

    ACE_Reactor::instance()->register_handler( SIGINT, mutateTimer1);
    ACE_Reactor::instance()->register_handler( SIGTSTP, mutateTimer2);


    // "run" the timer.
    Timer::instance()->wait_for_event();

    return 0;

    }

     

    Dynamische Aspekte

    • Die Applikation registriert einen konkreten Eventhander beim Reaktor. Der Eventhandler drückt durch sein Implementierung aus, auf welche Art von Events er reagieren will. Typischerweise heißen die hook-Methoden handle_*, wie handle_input, handle_timeout, handle_put,... .
    • Durch eine get_handle des konkreten Eventhandlers Methode holt sich der Reaktor den spezifischen Handler.
    • Wenn alle Handles registriert sind, startet die Applikaton die Eventloop des Reaktors. Der Reaktor überwacht nun die Menge aller registrierten Handler auf das Eintreffen von indication Events .
    • Sobals ein Event auftritt, übergibt der synchrone event demultiplexer die Kontrolle an den Reaktor.
    • Der Reaktor benützt die Handles als Schlüssel, um die entsprechenden Eventhandler aufzurufen (demultiplex) und auf die hook Methode auszurufen (dispatch).
    • Die spezifische Methode des Eventhandler bearbeitet die Anfrage direkt auf dem Handle.

    Sichten des Programmierers

    • Reactor Pattern:
      reactor.jpg

    Anwendungsentwickler

    Ich will netzwerktransparent wissen, wie lange die Design Pattern Runde noch dauert? Oder ein bißchen formaler:
    Implementiere einen Server, der auf eine Browser Anfrage ( HTTP-GET ) ein html Seite schickt, die die verbleibende Zeit bis zum Ende der Design Pattern Runde darstellt. Noch formaler
    Client macht eine HTTP-GET Request right Server nimmt Request an und dispatcht sie auf den Event Handler right Event Handler schickt die Antwort zum Client Dazu müssen drei Schritte als Anwendungsentwickler und Nutzer der Reaktor Struktur implementiert werden.
    Ich verwende den BaseHTTPServervon Python.

    Request Handler implementieren

    class RequestHandler(BaseHTTPRequestHandler):


    def do_GET(self):
    import datetime
    actTime= datetime.datetime.now()

    endTime= datetime.datetime( 2007,5,22,9)

    diffSeconds= (endTime-actTime).seconds
    self.send_response(200)
    self.send_header('Content-type', 'text/html')

    self.end_headers()
    self.wfile.write("""<?xml version="1.0" ?>

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>

    <title>Wie lange dauerts noch?</title>
    <script src="https://scwiki.science-computing.de/twiki/pub/TWiki/ChecklistPlugin/itemstatechange.js"
    language="javascript" type="text/javascript"></script></head>

    <body>

    <h1 align="center"><font size="10" color="#FF0000">Count down</font></h1>

    <p align="center"> <font size="6"> %s Sekunden noch bis zum Ende der Design Pattern Runde.</font> </p>

    </body>
    </html>""" %(str(diffSeconds)))

    Request Handler registrieren

    srvr = HTTPServer(("",4711),RequestHandler)

    Event loop laufen starten

    srvr.serve_forever()  

    Frameworkentwickler

    Ich will ein Reaktor Framework in Python entwickeln, das auf Input Events reagiert. Exemplarisch werden vier verschiedene Typen von Input Events gleichzeitig prozessiert und die entsprechenden Nachrichten in ähnlichnamige Dateien ins home geschrieben.
    1. stdin
      • jede stdin Eingabe erzeugt ein Event, das zur Prozessierung des Events führt
    2. lesen einer Datei
      • nach dem Einlesen der Datei wird der Handler wieder entfernt
    3. lesen einer url
      • nach dem Einlesen der Internetressource wird der Handler wieder entfernt
    4. HTTP - GET Anfrage
      • bei jedem stdin Event will ich wissen, wie lange die Design Pattern Runde noch dauert; dazu müssen periodisch folgende Schritte vollzogen werden
        • registriere den Event Handler, um den ReactorPattern Server zu fragen
        • darstellen des Ergebnisses auf stderr
        • deregistrieren des Event Handlers
    ##################
    #Event Handlers
    ##################

    import os
    import socket
    import sys
    import time


    class EventHandler:

    def handle_input(self,device):
    raise NotImplementedError

    def handle_output(self,device):
    raise NotImplementedError

    def handle_exception( self,device):
    raise NotImplmentedError

    def getHandle( self ):
    return NotImplementedError

    class InputEventHandler( EventHandler ):

    def __init__(self,device,dest):

    self.handleDevice= device
    self.outFile=open(dest,"a")

    firstLine= "Read from %s with handle %s \n" % ( device.name , device.fileno() )

    self.outFile.writelines([firstLine,"\n"])


    def handle_input(self,device):


    inp= device.readline().strip()
    self.outFile.write( inp + "\n" )

    self.outFile.flush()
    myReactor.registerHandler( InputToStderrEventHandler( urllib.urlopen("http://ackbar:4711"),

    os.getenv("HOME")+"/test.WieLangNoch" ) , "r")

    def getHandle( self ): return self.handleDevice

    class FileInputEventHandler( InputEventHandler ):

    def __init__(self,device,dest):

    self.handleDevice= device
    self.outFile=open(dest,"a")

    name=""
    try:
    name= device.name
    except:

    name= device.geturl()

    firstLine= "Read from %s with handle %s \n" % ( name , device.fileno() )

    self.outFile.writelines([firstLine,"\n"])


    def handle_input( self, device ):

    for line in device.readlines():
    self.outFile.write( line.strip() + "\n" )

    self.outFile.flush()
    Reactor().removeHandler( self ,"r" )

    class InputToStderrEventHandler( FileInputEventHandler ):

    def handle_input( self, device ):

    for line in device.readlines():
    self.outFile.write( line.strip() + "\n" )

    if line.startswith("<p align"):
    message= line.split(">")[2].split("<")[0]

    sys.stderr.write( message )
    self.outFile.flush()

    Reactor().removeHandler( self,"r")





    #############

    # Reactor
    #############

    class Singleton(object):
    def __new__(cls, *args, **kwds):

    it = cls.__dict__.get("__it__")
    if it is not None:

    return it
    cls.__it__ = it = object.__new__(cls)

    it.init(*args, **kwds)
    return it
    def init(self, *args, **kwds):

    pass



    import select

    class Reactor( Singleton ):

    readHandles={}
    writeHandles={}
    exceptHandles={}


    def registerHandler( self, eventHandler,eventTypes):

    handle= eventHandler.getHandle()
    handleId= handle.fileno()


    if "r" in eventTypes: Reactor.readHandles[handleId]= (handle,eventHandler)

    if "w" in eventTypes: Reactor.Reactor.writeHandles[handleId]= (handle,eventHandler)

    if "e" in eventTypes: Reactor.Reactor.exceptHandles[handleId]= (handle,eventHandler)


    def removeHandler( self, eventHandler ,eventTypes ):

    handle= eventHandler.getHandle()
    handleId= handle.fileno()


    if "r" in eventTypes: del Reactor.readHandles[handleId]

    if "w" in eventTypes: del Reactor.writeHandles[handleId]

    if "e" in eventTypes: del Reactor.exceptHandles[handleId]


    def handleEvents( self):

    while ( 1 ):

    rHandle, wHandle,eHandle= select.select( Reactor.readHandles.keys(), Reactor.writeHandles.keys(),
    Reactor.exceptHandles.keys() )

    print "all ready handle: Reactor.readHandles: %s Reactor.writeHandles: %s Reactor.exceptHandles: %s "
    %(rHandle,wHandle,eHandle)

    for han in rHandle:
    handleDevice= Reactor.readHandles[han][0]

    eventHandler= Reactor.readHandles[han][1]
    eventHandler.handle_input( handleDevice )

    for han in wHandle:
    handleDevice= Reactor.writeHandles[han][0]

    eventHandler= Reactor.writeHandles[han][1]
    eventHandler.handle_output( handleDevice )


    for han in eHandle:
    handleDevice= Reactor.exceptHandles[han][0]

    eventHandler= Reactor.exceptHandles[han][1]
    eventHandler.handle_exception( handleDevice )

    print "Reactor:handleEvents: waiting for input "

    import urllib

    myReactor=Reactor()
    myReactor.registerHandler( InputEventHandler( sys.stdin ,
    os.getenv("HOME")+"/test.stdin" ) ,"r")

    myReactor.registerHandler( FileInputEventHandler( open("/etc/services"),
    os.getenv("HOME")+"/test.services" ) ,"r")

    myReactor.registerHandler( FileInputEventHandler( urllib.urlopen("http://www.heise.de"),
    os.getenv("HOME")+"/test.heise" ) , "r")

    myReactor.handleEvents()

    Aspekte des Reaktor Frameworks

    Event Handler Interface festlegen
    class EventHandler:        

    def handle_input(self,device):
    raise NotImplementedError

    def handle_output(self,device):
    raise NotImplementedError

    def handle_exception( self,device):
    raise NotImplmentedError

    def getHandle( self ):
    return NotImplementedError
    Reaktor implementieren
    import select

    class Reactor( Singleton ):

    readHandles={}
    writeHandles={}
    exceptHandles={}


    def registerHandler( self, eventHandler,eventTypes):

    handle= eventHandler.getHandle()
    handleId= handle.fileno()


    if "r" in eventTypes: Reactor.readHandles[handleId]= (handle,eventHandler)

    if "w" in eventTypes: Reactor.Reactor.writeHandles[handleId]= (handle,eventHandler)

    if "e" in eventTypes: Reactor.Reactor.exceptHandles[handleId]= (handle,eventHandler)


    def removeHandler( self, eventHandler ,eventTypes ):

    handle= eventHandler.getHandle()
    handleId= handle.fileno()


    if "r" in eventTypes: del Reactor.readHandles[handleId]

    if "w" in eventTypes: del Reactor.writeHandles[handleId]

    if "e" in eventTypes: del Reactor.exceptHandles[handleId]


    def handleEvents( self):

    while ( 1 ):

    rHandle, wHandle,eHandle= select.select( Reactor.readHandles.keys(), Reactor.writeHandles.keys(),
    Reactor.exceptHandles.keys() )

    print "all ready handle: Reactor.readHandles: %s Reactor.writeHandles: %s Reactor.exceptHandles: %s "
    %(rHandle,wHandle,eHandle)

    for han in rHandle:
    handleDevice= Reactor.readHandles[han][0]

    eventHandler= Reactor.readHandles[han][1]
    eventHandler.handle_input( handleDevice )

    for han in wHandle:
    handleDevice= Reactor.writeHandles[han][0]

    eventHandler= Reactor.writeHandles[han][1]
    eventHandler.handle_output( handleDevice )


    for han in eHandle:
    handleDevice= Reactor.exceptHandles[han][0]

    eventHandler= Reactor.exceptHandles[han][1]
    eventHandler.handle_exception( handleDevice )

    print "Reactor:handleEvents: waiting for input "
    Um ein Eventhandler zu registrieren wird zusätzlich der Event Typ benötigt, für den sich der Event Handler interessiert.
    Durch die Registratur des Eventhandler ist es möglich, über den Filehandle ( z.B.: stdin = 0 ) sowohl das Fileobject, die Eventsource und den Eventhandler, die Anwendungslogik zu erhalten.
    In handle Events bedient sich der Reaktor dem nativen select Befehl um auf relevante Events registrieren zu können. handleEvents stellt die Eventloop des Reaktor dar, die, einmal gestartet, immer auf eingehende Events lauscht.

    Ausgabe, abhängig von den registrierten Event Handles

    • stdin wird registriert
      python reactorInput.py
      4
      all ready handle: Reactor.readHandles: [0] Reactor.writeHandles: [] Reactor.exceptHandles: []
      Reactor:handleEvents: waiting for input
    Erst durch die Eingabe der Zahl 4 wird die Eventloop prozessiert. Ein Eingabe Event Reactor.readHandles: [0]liegt nun vor.
    • stdin, Datei und Url Request werden registriert
      python reactorInput.py
      all ready handle: Reactor.readHandles: [4, 6] Reactor.writeHandles: [] Reactor.exceptHandles: []
      Reactor:handleEvents: waiting for input
      4
      all ready handle: Reactor.readHandles: [0] Reactor.writeHandles: [] Reactor.exceptHandles: []
      Reactor:handleEvents: waiting for input
    Die Ressourcen file und url sind beim Starten der Eventloop registriert, daher werden sie sofort prozessiert all ready handle: Reactor.readHandles: [4, 6] Reactor.writeHandles: [] Reactor.exceptHandles: [] . Da ich sie explizit deregistriere sind sie bei in dem Eintreten eines stdin-Events nicht mehr vorhanden all ready handle: Reactor.readHandles: [0] Reactor.writeHandles: [] Reactor.exceptHandles: []. Der Reaktor prozessiert nun nur noch den Filedescriptor 0, also stdin.
    • stdin, Datei , Url und HTTP-GET Request werden registriert
      all ready handle: Reactor.readHandles: [4, 6] Reactor.writeHandles: [] Reactor.exceptHandles: []
      Reactor:handleEvents: waiting for input
      4
      all ready handle: Reactor.readHandles: [0] Reactor.writeHandles: [] Reactor.exceptHandles: []
      Reactor:handleEvents: waiting for input
      all ready handle: Reactor.readHandles: [4] Reactor.writeHandles: [] Reactor.exceptHandles: []
      49661 Sekunden noch bis zum Ende der Design Pattern Runde.Reactor:handleEvents: waiting for input
    Die stdin Abfrage registriet nun einen neuen Eventhandler, der die mir die Frage beantwortert: Wie lange dauert noch die Design Pattern Runde? Dieser Request erhält wieder den Filedescriptor 4. all ready handle: Reactor.readHandles: [4] Reactor.writeHandles: [] Reactor.exceptHandles: []

    Implementierung

    Die Implementierung des Reaktor Patterns lässt sich in zwei Schichten unterteilen. Die Frameworkschicht, die die applikationsunabhängige demultiplex/dispatch Infrastruktur zur Verfügung stellt und die Applikationschicht, die die konkreten Eventhandler liefert. In der klassischen, einfachsten Form, geschieht das ganz Eventhandling in einem Prozeß.

     Definiere das Event Handler Interfaces

    Die Methoden des Event Handlers legen das Servcie-Interface des Reaktor Frameworks fest.
    1. bestimme den Typ des dispatchingZiels
      • verwende eine Event Handler Objekt oder eine Event Handle Funktion
    2. bestimme die Event Handling dispatching Strategie
      1. dispatch auf eine einzelne Methode
        ...
        virtual void handlle_event( Handle handle, Event_Type et)= 0;
        ...
      2. dispatch auf mehrere Methoden
        ...
        virtual void handle_input( Handle handle )=0;
        virtual void handle_output( Handle handle )=0;
        virtual void handle_timeout( Handle handle )=0;
        ...
      • das eine Methode Interface erlaubt es einfach, das Framework um neue Eventtypen zu erweitern
      • während bei handle_event die ganze Verteilungsstrategie mittels Bedingungen auf Applikationsebene definiert werden muß, geschieht der dispatch auf dem reichhaltigeren Interface automatisch auf Frameworkebene
      • insbesondere ist bei feingranularen Dispatch möglich, spezielle hook Methoden in konkreten Event Handlern zu überschreiben

     Definiere das Reaktor Interface

    Die Applikation nutzt einerseits das Reaktor Interface um die spezifischen Event Handler zu de/registrieren und andererseits die Event Loop zu starten. Gerne wird das Reaktor Interface als Singleton implementiert, das die Anfragen an die Reaktor Implementierung delegiert. Neben dem Event Handler erhält erhält die register_handler als zweites Argument den Event Type als Argument, für den sie sich interessiert.
    void Select_Reactor_Implementation::register_handler( EventHandler* eventHandler, Event_Type event_type )

     Implementiere das Reaktor Interface

    • entkopple das Reaktor Interface von seiner Implementierung durch eine Brücke right mehrere verschiedene Implementierung können unterstützt werden ( select, poll, WaitFormMultipleObjects , GuiEventLoops ,... )
    • wähle einen synchronen event demutliplexer aus
    int select( u_int max_handle_plus_1 , 
    fd_set *read_fds, fd_set * write_fds, fd_set *except_fds,

    timeval *timeout);
    • implementiere ein demultiplexing table
      • ein Eintrag soll von der Form < handle, event_handle, indication event type > sein, wobei handle als Schlüssel für den Event Handler bei einem indication event ( connect, expire, read,... ) verwendet wird
    • definiere die Reaktor Implementierung
    # select Server( only demultiplexing ) 
    def get_request(self):

    while self._running:
    log.info('select on listen socket')
    # demultiplex

    rs, ws, es = select.select([self.socket], [], [], 10)

    if rs:
    log.info('accepting new connection')
    # socketobject and address
    return self.socket.accept()
    log.info('ending request loop')

    return (None, None)

     Bestimme die Anzahl der Reaktoren, die man benötigt

    • in der Regel sollte der Reaktor ein Singleton sein, jedoch erlaubt win32 nur 64 Handles pro Reaktor
    • aus Echtzeitforderungen kann es nötig sein mehrere Reaktoren gleichzeitig laufen zu lassen; Trennung der Reaktoren nach Eventtypen

     Implementiere die konkreten Eventhandler

    • sie stellen die Anwendungslogik dar, im Gegensatz zu dem bisher vorgestellten Reaktor-Framework
    • statte die Eventhandler gegebenfalls mit einem Zustand aus; vgl. Beispiel Timer mit ACE
    • implementiere die Eventhandler Funktionalität

    Kritik

    • Vorteile
      • klare Trennung von Framework- und Applikationslogik
      • Modularität von eventgetriebenen Anwendungen durch verschieden Eventhandler
      • Portabilität durch Trennung von Interface und Implementierung des Reaktors
      • einfache Parallelität durch den synchronen event demutliplexers
    • Nachteile
      • setzt einen event demultiplexer voraus
      • Durchsatzprobleme bei lang laufenden Event Handler in single Threaded Applikation, den der Event Handler blockiert den Reaktor
      • schwierig zu debuggen und zu testen durch die inversion of control

    Verwendete Patterns - Techniken

    • ObserverPattern
      • der Event Handler wird informiert, sobald ein für ihn spezifisches Event auftritt
    • BridgePattern
      • der Reaktor hält sich eine spezifische Reaktor Implementierung, an die er die Aufrufe delegiert
    • TemplateMethodePattern
      • die handle_* Methoden als hook Methoden werden wohl in statisch typisierten Programmiersprachen in einer definierten Reihenfolge prozessiert
    • double Dispatch: registerHandler right getHandle

     

Mentoring

Stay Informed about my Mentoring

 

Rezensionen

Tutorial

Besucher

Heute 724

Gestern 3357

Woche 12287

Monat 39604

Insgesamt 3892318

Aktuell sind 38 Gäste und keine Mitglieder online

Kubik-Rubik Joomla! Extensions

Abonniere den Newsletter (+ pdf Päckchen)

Beiträge-Archiv

Sourcecode

Neuste Kommentare