2012-06-25 3 views
6

Una limitazione dell'implementazione di protobuf-net è che chiama gli stream sottostanti in modo sincrono. Non offrendo un'API asincrona, ad es. BeginSerialize/EndSerialize o equivalente TPL, siamo costretti a legare un thread in attesa di I/O di flusso sincrono.Serializzazione asincrona protobuf

Esiste un piano per offrire metodi asincroni in protobuf-net o, in alternativa, modi creativi attorno a questo problema?

risposta

5

No, non è attualmente supportato e sarebbe un lotto di lavoro.

Il mio suggerimento sarebbe: i dati del buffer voi stessi utilizzando le API asincroni, e poi, quando si hanno i dati, usare qualcosa come un MemoryStream deserializzare ...

In mia difesa, io non sono a conoscenza di qualsiasi serializzatore che offre qui un'API asincrona. In particolare, quando si parla di flussi lenti/asincroni, quello di solito significa "rete": e di solito si ha il problema di "framing" da considerare lì; protobuf-net non conoscerà i tuoi requisiti di framing ...

+0

C'è un flusso bufferizzato generico che blocca su async? Attualmente sto usando un approccio MemoryStream ma voglio parzialmente deserializzare l'intestazione del file (come in http://stackoverflow.com/questions/13342318/deserialize-part-of-a-binary-file) e non ho modo per sapere quanti byte ho bisogno di recuperare Async, solo il deserializzatore lo sa. – tozevv

+0

@tozevv sync-over-async? che * può * essere abbastanza pericoloso, ad essere onesti. Qual è l'origine dati sottostante qui? Quale fonte asincrona sta fornendo i dati? Un flusso sincrono-sincrono potrebbe probabilmente * essere scritto * abbastanza facilmente –

+0

Sì, non ho alcun problema con la scrittura. Sto leggendo da un file con un'intestazione e un corpo. Se so che la dimensione dell'intestazione è banale per leggere l'intestazione (ReadAsync) prima e solo se l'intestazione soddisfa una certa condizione legge anche il resto del corpo Async. Sia l'intestazione che i contenuti vengono serializzati usando l'eccellente (grazie per quello) implementazione dei buffer di protocollo. – tozevv

2

È possibile attendere Task.Run che eseguirà il codice sincrono nel pool di thread. Non è la soluzione più efficiente, ma è meglio del blocco. È anche possibile inviare il proprio CancellationToken-Task.Run:

await Task.Run(() => Serializer.SerializeWithLengthPrefix(
    stream, data, PrefixStyle.Base128), cancellationToken); 

In alternativa, è possibile utilizzare un abbastanza semplice metodo di supporto ripped from my JuiceStream library che ho presentato come parte di async feature request to protobuf-net:

await ProtobufEx.SerializeWithLengthPrefixAsync(
    stream, data, PrefixStyle.Base128, cancellationToken); 
await ProtobufEx.DeserializeWithLengthPrefixAsync<MyType>(
    stream, PrefixStyle.Base128, cancellationToken); 
+0

Sebbene non sia l'approccio più ideale, è una buona alternativa. – tunafish24

2

Sto usando protobuff sopra la Rete. Mentre la seguente soluzione non garantisce che blocco solito, lo fa rendere la vita molto meglio:

byte[] emptyByteArray = new Byte[0]; 
await stream.ReadAsync(emptyByteArray, 0, 0); 
TaskData d = Serializer.DeserializeWithLengthPrefix<TaskData>(stream, PrefixStyle.Base128); 

Perché ci assicuriamo che ci sono dati reali sul torrente prima di iniziare a deserializzare, sarà solo alla fine, quando il blocco lo stream contiene un messaggio parziale.

Edit: E possiamo usare un trucco simile per la serializzazione:

MemoryStream mstm = new MemoryStream(); 
Serializer.SerializeWithLengthPrefix(mstm, data, PrefixStyle.Base128); 
await stream.WriteAsync(mstm.GetBuffer(), 0, (int)mstm.Position); 

Come bonus, questo non garantisce di non bloccare.