2009-12-03 24 views
5

Ho bisogno di scrivere un server che riceverà istruzioni da altri moduli e intraprendere azioni a seconda delle istruzioni ricevute. L'efficienza è la mia preoccupazione principale. Così uso gen_server o scrivo il mio server. Con "mio server" Voglio dire una cosa del genere:Erlang: gen_server o il mio server personalizzato?

-module(myserver). 
-export([start/0, loop/0]). 

start() -> 
     spawn(myserver, loop, []). 

loop() -> 
    receive 
     {From, Msg} -> %Do some action here... ; 
     message2 -> %Do some action here...; 
     message3 -> %Do some action here...; 
     message4 -> %Do some action here...; 
     . 
     . 
     . 
     _-> ok 
    end, 
    loop(). 

Quindi, per usare myserver, io probabilmente registrare il processo con una denominazione registrata durante l'avvio, e poi ogni cliente invierà messaggi al server utilizzando questo pid .

Quindi dovrei utilizzare questo metodo o implementare il server utilizzando il comportamento gen_server? Ci sono dei vantaggi nell'uso di gen_server? Ma usando gen_server aggiungerai un sovraccarico, se confrontato con myserver?

+1

Sei stato molto preoccupato dell'efficienza per le ultime domande. Avete qualche numero di quali sono i requisiti di prestazione? – Christian

+1

Oh, e sicuramente andare con gen \ _server fino a quando non si può misurare dove sono i colli di bottiglia. – Christian

+0

Non ho numeri per quantificare i requisiti prestazionali per il sistema ora. Questo è un sistema sperimentale, quindi tutto quello che so per ora è che i server dovranno gestire un incredibile volume di traffico. Quindi sto cercando di essere più consapevole dell'efficienza e ottimizzare il più possibile. – ErJab

risposta

10

gen_server avrà un overhead trascurabile rispetto ai server auto-implementati, poiché richiede alcune chiamate di funzione aggiuntive per messaggio (una delle quali è dinamica). Non penso che dovresti considerare questo a questo punto di implementazione. Hai cambiato idea in qualsiasi momento, passare dal gen_server al tuo server dovrebbe essere semplice.

Quello che si ottiene con gen_server rispetto ad un semplice loop è:

  • debug (con SYS)
  • SASL accedendo
  • supporto ibernazione
  • supporto di aggiornamento codice
+1

Ma puoi aggiungere sys e proc_lib per rendere il tuo ciclo semplice compatibile con OTP e ottenere tutti i vantaggi elencati sopra. Vedi http://erlang.org/doc/design_principles/spec_proc.html e un buon esempio dal libro "scalability with eralang otp" cap. 10, https://github.com/francescoc/scalabilitywitherlangotp/blob/master/ch10/tcp_wrapper.erl –

3

Vorrei andare con il gen_server semplicemente perché è stato pensato tanto a farlo fare la cosa giusta in varie circostanze. Si prende cura dei dettagli difficili da ottenere. Immagino che lo gen_server potrebbe aggiungere qualche sovraccarico, ma ho smesso di fornire consigli sul rendimento. Se sei veramente interessato, implementa entrambi e misura la velocità, questo è l'unico modo sicuro per scoprirlo.

10

Vorrei andare con gen_server pure. Una volta che hai usato questa struttura, imparerai ad apprezzarne il valore. La funzione callback può essere un po 'imbarazzante (ad esempio handle_cast per le chiamate asincrone) ma alla fine ci si abitua.

Inoltre, mi sarebbe consigliato non impegnarsi in "ottimizzazione prematura" senza aver fatto qualche test. Probabilmente non vuoi sacrificare la leggibilità/manutenibilità per guadagni marginali di efficienza.

2

È può anche usare gen_server2 dai ragazzi dietro RabbitMQ.

E 'come gen_server tranne che per le seguenti regolazioni (dai commenti):

1) the module name is gen_server2 

2) more efficient handling of selective receives in callbacks 
gen_server2 processes drain their message queue into an internal 
buffer before invoking any callback module functions. Messages are 
dequeued from the buffer for processing. Thus the effective message 
queue of a gen_server2 process is the concatenation of the internal 
buffer and the real message queue. 
As a result of the draining, any selective receive invoked inside a 
callback is less likely to have to scan a large message queue. 

3) gen_server2:cast is guaranteed to be order-preserving 
The original code could reorder messages when communicating with a 
process on a remote node that was not currently connected. 
2

presumo dalla tua domanda che si sta scrivendo un server più "permanente".

In generale, il rotolamento del proprio server è più versatile e un po 'più veloce, se si ha ragione. Ma, e questo è un grande MA:

  • Si dovrà fare tutto da soli, il che aumenta il rischio di errori!

  • Se vuoi che il tuo server sia gestito in modo OTP, cosa che probabilmente fai se stai costruendo un sistema robusto, allora dovrai anche gestire tutto da solo. E fallo bene.

Se stavo facendo un server permanente vorrei iniziare utilizzando gen_server e solo fallback e rotolare il mio se mi imbatto in serie difficoltà nell'attuazione quello che mi serve.

I server di breve durata sono un'altra questione.