8

protobuf-net 実装の制限は、基になるストリームを同期的に呼び出すことです。BeginSerialize/EndSerialize や同等の TPL などの非同期 API を提供しないことで、同期ストリーム I/O を待機しているスレッドを拘束せざるを得なくなります。

protobuf-net で非同期メソッドを提供する計画はありますか、またはこの問題を回避する創造的な方法はありますか?

4

3 に答える 3

7

いいえ、それは現在サポートされておらず、大変な作業になります。

私の提案は次のとおりです。非同期APIを使用して自分でデータをバッファリングし、データを取得たら、のようなものを使用MemoryStreamして逆シリアル化します...

私の弁護では、ここで非同期 API を提供する他のシリアライザーを認識していません。特に、低速/非同期ストリームについて話すとき、それは通常「ネットワーク」を意味します。通常、そこで考慮すべき「フレーミング」の問題があります。protobuf-net はフレーミング要件を認識しません...

于 2012-06-25T10:29:20.667 に答える
3

ネットワーク経由でプロトバフを使用しています。次の解決策は、ブロックしないことを保証するものではありませんが、人生をはるかに良くします:

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

逆シリアル化を開始する前にストリームに実際のデータがあることを確認するため、ストリームに部分的なメッセージが含まれている場合にのみブロックされます。

編集:そして、シリアライゼーションにも同様のトリックを使用できます:

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

おまけとして、これは決してブロックしないことを保証します。

于 2015-02-17T16:35:51.970 に答える
2

Task.Runスレッド プールで同期コードが実行されるのを待つことができます。これは最も効率的な解決策ではありませんが、ブロックするよりはましです。CancellationTokenに提出することもできますTask.Run:

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

または、非同期機能リクエストの一部として protobuf-net に送信した JuiceStream ライブラリから取得したかなり単純なヘルパー メソッドを使用することもできます。

await ProtobufEx.SerializeWithLengthPrefixAsync(
    stream, data, PrefixStyle.Base128, cancellationToken);
await ProtobufEx.DeserializeWithLengthPrefixAsync<MyType>(
    stream, PrefixStyle.Base128, cancellationToken);
于 2014-05-20T20:20:33.813 に答える