2009-09-30 8 views
7

Vorrei sapere qual è il modo ottimale di archiviare alcuni tipi di dati comuni che non sono stati inclusi nell'elenco supportato dai buffer del protocollo.Quali sono i modi migliori per utilizzare decimali e datetime con i buffer del protocollo?

  • datetime (secondi precisione)
  • datetime (millisecondi precisione)
  • decimali con precisione fissa
  • decimali con una precisione variabile
  • un sacco di valori bool (se hai un sacco di loro sembra che Avrai 1-2 overhead per ciascuno di essi a causa dei loro tag

Anche l'idea è di mapparli molto facilmente da correggere i tipi di dati C++/Python/Java.

risposta

3

La logica del design protobuf è più probabile che mantenga il supporto del tipo di dati il ​​più possibile "nativo", così che in futuro sarà facile adottare nuove lingue. Suppongo che potrebbero fornire tipi di messaggi in-build, ma dove si disegna la linea?

La mia soluzione era quella di creare due tipi di messaggi:

DateTime 
TimeSpan 

questo è solo perché vengo da un background C#, in cui vengono prese queste tipologie per scontato.

In retrospettiva, TimeSpan e DateTime potrebbe essere stato eccessivo, ma era un modo "economico" di evitare la conversione da h/m/s a ​​se viceversa; Detto questo, sarebbe stato semplice da implementare solo una funzione di utilità quali:

int TimeUtility::ToSeconds(int h, int m, int s) 

Bklyn, indicate che la memoria heap viene utilizzato per i messaggi annidati; in alcuni casi questo è chiaramente molto valido: dovremmo sempre essere consapevoli di come viene utilizzata la memoria. Ma, in altri casi, questo può essere di minore preoccupazione, in cui siamo più preoccupati della facilità di implementazione (suppongo che questa sia la filosofia Java/C#).

C'è anche un piccolo svantaggio nell'usare tipi non intrinsechi con il protobuf TextFormat::Printer; non è possibile specificare il formato in cui viene visualizzata, in modo che sarà simile a:

my_datetime { 
    seconds: 10 
    minutes: 25 
    hours: 12 
} 

... che è troppo prolisso per alcuni. Detto questo, sarebbe più difficile da leggere se fosse rappresentato in pochi secondi.

Per concludere, direi:

  • Se siete preoccupati per la memoria/parsing efficienza, uso secondi/millisecondi.
  • Tuttavia, se la facilità di implementazione è l'obiettivo, utilizzare i messaggi annidati (DateTime, ecc.).
2

Siamo spiacenti, non una risposta completa, ma un "me troppo".

Penso che questa sia una grande domanda, una mi piacerebbe una risposta a me stesso. L'incapacità di descrivere in modo nativo i tipi fondamentali come datetimes e (per le applicazioni finanziarie) i decimali a virgola fissa, o mapparli a tipi specificati dalla lingua o definiti dall'utente è un vero assassino per me. Mi ha più o meno impedito di poter usare la libreria, che altrimenti ritengo sia fantastica.

Dichiarare il proprio messaggio "DateTime" o "FixedPoint" nel proto grammar non è realmente una soluzione, poiché sarà comunque necessario convertire manualmente la rappresentazione della propria piattaforma in/dagli oggetti generati, che è soggetta a errori. Inoltre, questi messaggi nidificati vengono archiviati come puntatori agli oggetti allocati su heap in C++, che è estremamente inefficiente quando il tipo sottostante è fondamentalmente solo un numero intero a 64 bit.

In particolare, vorrei essere in grado di scrivere qualcosa del genere nei miei file proto:

message Something { 
    required fixed64 time = 1 [cpp_type="boost::posix_time::ptime"]; 
    required int64 price = 2 [cpp_type="fixed_point<int64_t, 4>"]; 
    ... 
}; 

e sarei tenuto a fornire qualsiasi colla era necessario convertire questi tipi da/per fixed64 e int64 in modo che la serializzazione funzionasse. Forse con qualcosa come adobe::promote?

3

Ecco alcune idee basate sulla mia esperienza con un protocollo filo simile a Protocol Buffers.

datetime (secondi precisione)

datetime (millisecondi di precisione)

Penso che la risposta a questi due sarebbe stato lo stesso, si sarebbe solo in genere a che fare con una gamma più ridotta di numeri nel caso della precisione dei secondi.

Utilizzare un sint64/sfixed64 per memorizzare l'offset in secondi/millisecondi da un'epoca ben nota come GMT 1/1/1970 di mezzanotte. Ecco come gli oggetti Date sono internally represented in Java. Sono sicuro che ci sono analoghi in Python e C++.

Se sono necessarie informazioni sul fuso orario, passare la data/l'ora in termini di UTC e modellare il fuso orario pertinente come un campo stringa separato. Per questo, è possibile utilizzare gli identificatori da Olson Zoneinfo database poiché è diventato piuttosto standard.

In questo modo si dispone di una rappresentazione canonica per data/ora, ma è possibile anche localizzarsi a qualsiasi fuso orario sia pertinente.

decimali con precisione fissa

Il mio primo pensiero è quello di utilizzare una stringa simile a come si costruisce oggetti decimale da pacchetto decimale di Python. Suppongo che potrebbe essere inefficiente rispetto ad alcune rappresentazioni numeriche.

Potrebbero esserci soluzioni migliori a seconda del dominio su cui si sta lavorando. Ad esempio, se stai modellando un valore monetario, forse puoi usare un uint32/64 per comunicare il valore in centesimi anziché importi in dollari frazionari.

Ci sono anche alcuni suggerimenti utili in this thread.

decimali con una precisione variabile

non Vuol buffer protocollo già supportano questo con galleggiante/doppio tipi scalari? Forse ho frainteso questo punto.

In ogni caso, se si ha la necessità di aggirare questi tipi scalari, è possibile codificare utilizzando IEEE-754 in uint32 o uint64 (float vs double rispettivamente). Ad esempio, Java allows you to extract the IEEE-754 representation e vice versa da oggetti Float/Double. Esistono meccanismi analoghi in C++/Python.

un sacco di valori bool (se avete un sacco di loro sembra che avrete 1-2 byte overhead per ciascuno di loro a causa di loro tag.

Se sei preoccupato per i byte sprecati sul filo, è possibile utilizzare bit-masking techniques per comprimere molti booleani in un singolo uint32 o uint64

Perché non c'è supporto di prima classe nei buffer di protocollo, tutte queste tecniche richiedono un po 'di gentlemen' contratto tra agenti . Forse l'utilizzo di una convenzione di denominazione sui campi come "_dttm" o "_mask" potrebbe aiutare a comunicare quando un determinato campo ha una semantica di codifica aggiuntiva oltre al comportamento predefinito dei buffer del protocollo.

1

Per datetime con risoluzione di millisecondo ho usato un int64 che ha il datetime come YYYYMMDDHHMMSSmmm. Ciò lo rende sia conciso e leggibile, e sorprendentemente, durerà a lungo.

Per i decimali, ho utilizzato byte[], sapendo che non esiste una rappresentazione migliore che non sia dannosa.