首页 > 解决方案 > 将数组映射到定义的段/字段

问题描述

我有一个类型的数组double[],我希望能够映射到预定义的段中。每个段都与一组double值有关,这些值可以通过自定义类型适配器与任意类型进行序列化。例如,考虑以下数组:

var data = new double[] {
  0, 0, 1, 0, 0, 0, 0,   // DayOfWeek (Deserializes to DayOfWeek.Tuesday)
  0.5,                   // Deserializes to double
  0.3, 0.7,              // Deserializes to Tuple<double,double>
};

有了这些数据,我希望能够将每组数组元素拆分为适当的Memory<double>对象。

我目前的计划是拥有三个包装器结构:FieldFieldSetMappedArray,它们目前是这样定义的(但仍在进行中):

public readonly struct Field
{
   public readonly Guid Id;
   public readonly string Name;
   public readonly double Value;
   private readonly int _hash;

   public Field( string name )
   {
     Id = Guid.NewGuid();
     Name = name;
     Value = default;

     _hash = Name.GetHashCode();
   }

   private Field( Field template, double value )
   {
     Id = template.Id;
     Name = template.Name;
     Value = value;

     _hash = template._hash;
   }
}

public struct FieldSet
{
  public readonly Guid Id;
  public readonly string Name;
  public readonly Field[] Fields;
  private readonly Memory<double> _data;
  private readonly int _hash;

  public double this[ int index ] => _data[ index ];

  public Field this[ string name ]
  {
    get => throw new NotImplementedException();
  }

  public Field this[ Field field ]
  {
    get => throw new NotImplementedException();
  }

  public FieldSet( string name, Field[] fields )
  {
    Id = Guid.NewGuid();
    Name = name;
    Fields = fields;

    _data = null;
    _hash = name.GetHashCode();
  }

  private FieldSet( FieldSet template, Memory<double> data )
  {
    Id = template.Id;
    Name = template.Name;
    fields = template.Fields;

    _data = data;
    _hash = template._hash;
  }
}

public struct MappedArray
{
  private Memory<double> _data;

  public double this[ int index ] => _data[ index ];

  public FieldSet this[ string name ]
  { // Lookup via name
    get => throw new NotImplementedException();
  }

  public FieldSet this[ FieldSet set ]
  { // Lookup via Id
    get => throw new NotImplementedException();
  }

}

有了这些,我有几个目标:

第二个目标是我最挣扎的目标。这个映射系统将在非常热的代码路径上运行(实时神经网络输入/输出),我担心 GC 在所有分配和解除分配方面都会遇到困难,所以我会喜欢尽可能重用FieldFieldSet因为它们的目的是将数组抽象为易于使用的结构。

有了这个,主要问题是:我如何设计它以便可以重用“模式”结构?本质上,拥有定义架构的静态FieldSetField实例,然后能够访问这些段,所有这些都无需分配和解除分配。在下面@Pressacco 的回复中,浮现在脑海中的是享元模式,在哪里回收,并FieldSet附加了 a。FieldMemory<double>

标签: c#

解决方案


这绝不是答案,但希望它能为您指明正确的方向。

反序列化

我将从查看System.Runtime名称空间开始。特别是System.Runtime.InteropServicesStructLayout中的属性。几点注意事项:

  • 考虑创建一个沙盒应用程序以确保您获得预期的性能。
  • StructLayout有它的限制...确保它们不会影响你。

表现

考虑创建一个资源池,您可以在其中回收对象实例。如果您不分配和取消分配内存......那么您将不会受到性能影响。我相信设计模式可以称为Object Pool

伪代码看起来像

var message = resourcePool.GetInstance();
MessageFactory.Create(message, serializedData);
...
// do work
...
resourcePool.ReturnInstance(message); // the allocated memory can now be used to de-serialize a future message

最后,尽量避免进行过早的性能优化。


推荐阅读