2012-06-25 6 views
6

Ograniczeniem implementacji protobuf-net jest synchronizacja wywoływanych strumieni bazowych. Nie oferując asynchronicznego interfejsu API, np. BeginSerialize/EndSerialize lub równoważnik TPL, jesteśmy zmuszeni związać wątek oczekujący na synchroniczne operacje we/wy.Asynchroniczna serializacja protobuf

Czy istnieje plan oferowania metod asynchronicznych w protobuf-net, lub alternatywnie wszelkie kreatywne sposoby rozwiązania tego problemu?

Odpowiedz

5

Nie, to nie jest obecnie obsługiwane i będzie to część z pracy.

Moja propozycja to: dane buforowe samodzielnie za pomocą API async, a następnie gdy masz dane, należy użyć coś jak MemoryStream deserializacji ...

W mojej obronie, nie jestem świadomy dowolnego serializera innego, który oferuje tutaj interfejs API asynchronicznego. W szczególności, gdy mówimy o strumieniach powolnych/asynchronicznych, ten zwykle oznacza "sieć": i zazwyczaj masz problem "kadrowania", aby to rozważyć; protobuf-net nie będzie znać twoich wymagań ramkowania ...

+0

Czy istnieje ogólny bufor buforowany blokujący asynchronizację? Obecnie używam podejścia MemoryStream, ale chcę częściowo deserializować nagłówek pliku (jak w http://stackoverflow.com/questions/13342318/deserialize-part-of-a-binary-file) i nie mam sposób, aby wiedzieć, ile bajtów potrzebuję do pobrania Async, wie tylko deserializer. – tozevv

+0

@tozevv sync-over-async? że * może * być dość niebezpieczne, szczerze mówiąc. Jakie jest tutaj źródło danych? Jakie źródło asynchroniczne dostarcza dane? Strumień synchronizacji po asynchronizacji może być prawdopodobnie * zapisany * z wystarczającą łatwością –

+0

Tak, nie mam problemu z pisaniem. Czytam z pliku z nagłówkiem i treścią. Jeśli wiem, rozmiar nagłówka jest banalnie prosty, aby odczytać nagłówek (ReadAsync) pierwszy i tylko wtedy, gdy nagłówek spełnia pewien warunek, przeczytaj resztę ciała także Asynchronicznie. Zarówno nagłówek, jak i zawartość są serializowane za pomocą znakomitej (dzięki za to) implementacji buforów protokołu. – tozevv

2

Możesz oczekiwać Task.Run, który uruchomi kod synchroniczny w puli wątków. To nie jest najbardziej wydajne rozwiązanie, ale jest lepsze niż blokowanie. Można nawet dodać własną CancellationToken do Task.Run:

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

Alternatywnie, można użyć dość prosta metoda pomocnika ripped from my JuiceStream library że mam przedłożone jako część async feature request to protobuf-net:

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

Chociaż nie jest to najbardziej idealne podejście, jest to dobra alternatywa. – tunafish24

2

używam protobuff nad sieć. Natomiast następujące rozwiązanie nie gwarantuje to przyzwyczajenie blok, to czyni życie znacznie lepiej:

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

Ponieważ dbamy istnieje rzeczywiste dane dotyczące strumienia zanim zaczniemy deserializowania, to tylko skończyć blokowanie kiedy strumień zawiera częściową wiadomość.

Edit: I możemy zastosować podobną sztuczkę dla serializacji:

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

Jako bonus, ten nie gwarantuje, że nigdy nie zablokować.