【发布时间】:2016-07-27 22:49:15
【问题描述】:
我目前正在从事一个基于其他代码生成代码的项目。本质上将编程语言本身用作 DSL。
生成器目标之一是 binary DataContract serializer 和为以下类生成的 ToBytes
[DataContract]
public partial class Root
{
[DataMember]
public int Number { get; set; }
[DataMember]
public Partial[] Partials { get; set; }
[DataMember]
public IList<ulong> Numbers { get; set; }
}
变成这样:
public int Size
{
get
{
var size = 8;
// Add size for collections and strings
size += Partials.Sum(entry => entry.Size);
size += Numbers.Count * 8;
return size;
}
}
public byte[] ToBytes()
{
var index = 0;
var bytes = new byte[Size];
return ToBytes(bytes, ref index);
}
public byte[] ToBytes(byte[] bytes, ref int index)
{
// Convert Number
Buffer.BlockCopy(BitConverter.GetBytes(Number), 0, bytes, index, 4);;
index += 4;
// Convert Partials
// Two bytes length information for each dimension
Buffer.BlockCopy(BitConverter.GetBytes((ushort)(Partials == null ? 0 : Partials.Length)), 0, bytes, index, 2);
index += 2;
foreach(var value in Partials ?? Enumerable.Empty<Partial>())
{
value.ToBytes(bytes, ref index);
}
// Convert Numbers
// Two bytes length information for each dimension
Buffer.BlockCopy(BitConverter.GetBytes((ushort)(Numbers == null ? 0 : Numbers.Count)), 0, bytes, index, 2);
index += 2;
foreach(var value in Numbers ?? Enumerable.Empty<ulong>())
{
Buffer.BlockCopy(BitConverter.GetBytes(value), 0, bytes, index, 8);;
index += 8;
}
return bytes;
}
现在即使很难,这真的很快,我正在寻找一种方法来加速 Buffer.BlockCopy(BitConverter.GetBytes 的所有使用。为每次转换创建一个新的小byte[] 然后在我已经拥有byte[] 和位置时复制它似乎仍然是浪费资源。
有什么想法可以最好地改进代码吗?
更新:基于@adrianm 评论,我将用for 循环替换foreach 数组,并在if 语句中包装可空类型。不希望使用 another thread 中的结构。我宁愿使用类和 [DataContract] 属性。另外为了符合 Linux 规范,我不能使用 WinApi。
Update2:添加了生成的其余代码。感谢评论未来的版本将包括
if (index + Size > bytes.Length)
// Some error handling
【问题讨论】:
-
分配和字节复制真的很快。我的猜测是,如果您专注于代码中的其他部分,例如使用
for loops而不是foreach和if而不是?? Enumerable.Empty,您可以提高速度。 -
通常是
struct和Marshal.StructureToPtr,如果你需要fast,那么winapi方法是the way去。 -
@adrianm 好点。我使用了
foreach,因为它与所有集合兼容,但查看ArrayEnumerator,这可能是一个令人费解的选择。感谢您的反馈。 -
@Sinatr 老实说我不知道这一点,但似乎它不能完全涵盖我想做的事情。同样使用结构意味着每次分配到某个地方时都会复制它。如果一个大的实例得到了很多传递,这将是一个性能损失,不是吗?并且在 Linux/Mono 上使用 WinApi 将无法正常工作,对吗?
-
BitConverter并不神奇。MyBitConverter.GetBytes(int, byte[] buffer, int offset)写起来很简单。相关:stackoverflow.com/questions/2527018
标签: c# binary unsafe bitconverter