8

protobuf-net 实现的一个限制是它同步调用底层流。由于不提供异步 API,例如 BeginSerialize/EndSerialize 或 TPL 等价物,我们被迫占用等待同步流 I/O 的线程。

有没有计划在 protobuf-net 中提供异步方法,或者有什么创造性的方法来解决这个问题?

4

3 回答 3

7

不,这目前不受支持,而且工作量很大

我的建议是:使用异步 API 自己缓冲数据,然后你有数据时,使用类似 a 的东西MemoryStream来反序列化......

在我的辩护中,我不知道这里有任何其他提供异步 API 的序列化程序。特别是,在谈论慢速/异步流时,这通常意味着“网络”:您通常会在那里考虑“框架”问题;protobuf-net 不会知道您的框架要求...

于 2012-06-25T10:29:20.667 回答
3

我在网络上使用 protobuff。虽然以下解决方案不能保证它不会阻塞,但它确实让生活变得更好:

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将在线程池中运行同步代码。这不是最有效的解决方案,但比阻塞要好。您甚至可以将自己的提交CancellationTokenTask.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 回答