Sérialisation protobuf asynchrone

Une limitation de l’implémentation de protobuf-net est qu’elle appelle les stream sous-jacents de manière synchrone. En n’offrant pas une API asynchrone, par exemple BeginSerialize / EndSerialize ou un équivalent TPL, nous sums obligés d’attacher un thread en attente d’E / S de stream synchrones.

Est-il prévu de proposer des méthodes asynchrones dans protobuf-net ou, au contraire, des solutions créatives pour résoudre ce problème?

Non, ce n’est pas actuellement pris en charge et cela demanderait beaucoup de travail.

Ma suggestion serait la suivante: mettez les données vous-même en mémoire tampon à l’aide des API asynchrones, puis, lorsque vous disposez des données, utilisez quelque chose comme un MemoryStream pour désérialiser …

Pour ma défense, je ne connais aucun autre sérialiseur proposant une API asynchrone ici. En particulier, lorsque vous parlez de stream lents / asynchrones, cela signifie généralement “réseau”: vous avez généralement la question du “cadrage” à prendre en compte; Protobuf-net ne saura pas vos besoins de cadrage …

Vous pouvez attendre Task.Run pour exécuter le code synchrone dans le pool de threads. Ce n’est pas la solution la plus efficace, mais c’est mieux que le blocage. Vous pouvez même soumettre votre propre CancellationToken à Task.Run :

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

Vous pouvez également utiliser une méthode d’assistance assez simple, extraite de la bibliothèque JuiceStream que j’ai soumise dans le cadre d’ une demande de fonctionnalité asynchrone à protobuf-net :

 await ProtobufEx.SerializeWithLengthPrefixAsync( stream, data, PrefixStyle.Base128, cancellationToken); await ProtobufEx.DeserializeWithLengthPrefixAsync( stream, PrefixStyle.Base128, cancellationToken); 

J’utilise protobuff sur le réseau. Bien que la solution suivante ne garantisse pas son blocage, elle améliore considérablement la vie:

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

Parce que nous nous assurons qu’il y a des données réelles sur le stream avant de commencer la désérialisation, il ne sera bloqué que lorsque le stream contiendra un message partiel.

Edit: Et nous pouvons utiliser une astuce similaire pour la sérialisation:

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

En prime, celui-ci garantit de ne jamais bloquer.