【发布时间】:2020-02-19 06:47:05
【问题描述】:
我与cellular automata 合作。我的工作回购是here。基本结构是
1) 一个网格 2) 细胞,可能有 3) 代理。
代理根据一组规则行事,通常一个人为代理指定“状态”(不同状态的代理有不同的规则)。一个(相对)知名的 CA 是 game of life。
我正在尝试扩展一些东西,并在我的 CA 中加入其他类型的“属性”,主要是为了模拟各种现象(想象一个消耗植物代理的动物代理,以及植物的“生物质”或具有你减少了)。
为此,我合并了一个普通字典,其中字符串作为键,一个名为 CAProperty 的结构作为值。结构如下:
public struct CAProperty
{
public readonly string name;
public readonly dynamic value;
//public readonly Type type;
public CAProperty(string name, dynamic value)
{
this.name = name;
this.value = value;
}
}
(注意:以前我有一个“类型”变量来在运行时启用准确的输入......但为了解决这篇文章中的问题,我删除了它。事实上,它需要重新添加)
这很好。但是,我正在尝试使用大网格尺寸做一些工作。 100x100。 1000x1000。 5000x5000,或 2500 万个细胞(和代理)。那将是 2500 万个字典。
查看图片:来自 Visual Studio 的内存快照,用于 4000x4000 网格或 1600 万个代理(我尝试了 5000x5000,但 Visual Studio 不允许我拍摄快照)。
在右侧,可以清楚地看到调试器正在读取 8 GB 的内存使用情况(我在发布版本中尝试过此操作以查看 6875 MB 的使用情况)。但是,当我计算快照第三列中的所有内容时,我发现不到 4 GB。
为什么总内存使用量与存储在内存中的对象大小之间存在如此巨大的差异?
另外:我如何优化内存使用(主要是字典 - 是否有另一个具有类似行为但内存使用量较低的集合)?
编辑:对于三个“组件”(网格、单元格、代理)中的每一个,我都有一个类。它们都继承自原始的 CAEntity 类。全部如下所示。
public abstract class CAEntity
{
public CAEntityType Type { get; }
public Dictionary<string, dynamic> Properties { get; private set; }
public CAEntity(CAEntityType type)
{
this.Type = type;
}
public CAEntity(CAEntityType type, Dictionary<string, dynamic> properties)
{
this.Type = type;
if(properties != null)
{
this.Properties = new Dictionary<string, dynamic>(properties);
}
}
}
public class CAGraph:CAEntity
{
public ValueTuple<ushort, ushort, ushort> Dimensions { get; }
public CAGraphCell[,,] Cells { get;}
List<ValueTuple<ushort, ushort, ushort>> AgentCells { get; set; }
List<ValueTuple<ushort, ushort, ushort>> Updates { get; set; }
public CA Parent { get; private set; }
public GridShape Shape { get; }
//List<double> times = new List<double>();
//System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
public CAGraph (CA parent, ValueTuple<ushort, ushort, ushort> size, GridShape shape):base(CAEntityType.Graph)
{
this.Parent = parent;
this.Shape = shape;
AgentCells = new List<ValueTuple<ushort, ushort, ushort>>();
Updates = new List<ValueTuple<ushort, ushort, ushort>>();
Dimensions = new ValueTuple<ushort, ushort, ushort>(size.Item1, size.Item2, size.Item3);
Cells = new CAGraphCell[size.Item1, size.Item2, size.Item3];
for (ushort i = 0; i < Cells.GetLength(0); i++)
{
for (ushort j = 0; j < Cells.GetLength(1); j++)
{
for (ushort k = 0; k < Cells.GetLength(2); k++)
{
Cells[i, j, k] = new CAGraphCell(this, new ValueTuple<ushort, ushort, ushort>(i, j, k));
}
}
}
}
public CAGraph(CA parent, ValueTuple<ushort, ushort, ushort> size, GridShape shape, List<ValueTuple<ushort, ushort, ushort>> agents, CAGraphCell[,,] cells, Dictionary<string, dynamic> properties) : base(CAEntityType.Graph, properties)
{
Parent = parent;
Shape = shape;
AgentCells = agents.ConvertAll(x => new ValueTuple<ushort, ushort, ushort>(x.Item1, x.Item2, x.Item3));
Updates = new List<ValueTuple<ushort, ushort, ushort>>();
Dimensions = new ValueTuple<ushort, ushort, ushort>(size.Item1, size.Item2, size.Item3);
Cells = new CAGraphCell[size.Item1, size.Item2, size.Item3];
for (ushort i = 0; i < size.Item1; i++)
{
for (ushort j = 0; j < size.Item2; j++)
{
for (ushort k = 0; k < size.Item3; k++)
{
//if(i == 500 && j == 500)
//{
// Console.WriteLine();
//}
Cells[i, j, k] = cells[i, j, k].Copy(this);
}
}
}
}
}
public class CAGraphCell:CAEntity
{
public CAGraph Parent { get; set; }
public CAGraphCellAgent Agent { get; private set; }
public ValueTuple<ushort, ushort, ushort> Position { get; private set; }
//private Tuple<ushort, ushort, ushort>[][] Neighbors { get; set; }
//System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
public CAGraphCell(CAGraph parent, ValueTuple<ushort, ushort, ushort> position):base(CAEntityType.Cell)
{
this.Parent = parent;
this.Position = position;
//this.Neighbors = new Tuple<ushort, ushort, ushort>[Enum.GetNames(typeof(CANeighborhoodType)).Count()][];
}
public CAGraphCell(CAGraph parent, ValueTuple<ushort, ushort, ushort> position, Dictionary<string, dynamic> properties, CAGraphCellAgent agent) :base(CAEntityType.Cell, properties)
{
this.Parent = parent;
this.Position = position;
if(agent != null)
{
this.Agent = agent.Copy(this);
}
}
}
public class CAGraphCellAgent:CAEntity
{
// have to change...this has to be a property? Or no, it's a CAEntity which has a list of CAProperties.
//public int State { get; set; }
public CAGraphCell Parent { get; set; }
//System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
public CAGraphCellAgent(CAGraphCell parent, ushort state):base(CAEntityType.Agent)
{
this.Parent = parent;
AddProperty(("state", state));
}
public CAGraphCellAgent(CAGraphCell parent, Dictionary<string, dynamic> properties) :base(CAEntityType.Agent, properties)
{
this.Parent = parent;
}
}
【问题讨论】:
-
那么字典键和 CAProperty 名称之间有区别吗?如果是,为什么?如果没有,为什么不是
Dictionary<string,dynamic>? -
...不,没有区别。最初我计划包含 Type 变量,但也许这不是绝对必要的。我打算让这个结构支持数字类型和布尔值,但也许我可以将它限制为数字类型(动态可以可靠地键入它们)。我试一试,切换到 Dictionary
。谢谢。 -
我尝试消除 CAProperty 结构并只使用 Dictionary
,但它似乎使用了大约相同数量的内存。
标签: c# dictionary memory simulation cellular-automata