Sve*_*ven 11 c# arrays initialization
我有3*.dat文件(346KB,725KB,1762KB),它们填充了一个json-string"big"int-Arrays.
每次创建对象(多次)时,我都会使用这三个文件并将 JsonConvert.DeserializeObject数组反序列化为对象.
我想过使用二进制文件而不是json-string,或者我可以直接保存这些数组吗?我不需要使用这些文件,它只是当前保存数据的位置.我很乐意更快地切换到任何东西.
加快这些对象初始化的不同方法有哪些?
最快的方法是手动序列化数据.
一种简单的方法是创建一个FileStream,然后将其包装在BinaryWriter/BinaryReader中.
您可以访问功能,写入基本数据结构(numbers,string,char,byte[]和char[]).
编写一个简单的方法int[](如果是固定大小则不必要)是通过在数组的长度前加上int/long(取决于大小,unsigned实际上没有任何优势,因为数组使用signed数据类型作为它们的长度)存储).然后写下所有的整数.
编写所有整数的两种方法是:
1.简单地遍历整个数组.
2.将其转换为a byte[]并使用它编写BinaryWriter.Write(byte[])
以下是如何实现它们的方法:
// Writing
BinaryWriter writer = new BinaryWriter(new FileStream(...));
int[] intArr = new int[1000];
writer.Write(intArr.Length);
for (int i = 0; i < intArr.Length; i++)
writer.Write(intArr[i]);
// Reading
BinaryReader reader = new BinaryReader(new FileStream(...));
int[] intArr = new int[reader.ReadInt32()];
for (int i = 0; i < intArr.Length; i++)
intArr[i] = reader.ReadInt32();
// Writing, method 2
BinaryWriter writer = new BinaryWriter(new FileStream(...));
int[] intArr = new int[1000];
byte[] byteArr = new byte[intArr.Length * sizeof(int)];
Buffer.BlockCopy(intArr, 0, byteArr, 0, intArr.Length * sizeof(int));
writer.Write(intArr.Length);
writer.Write(byteArr);
// Reading, method 2
BinaryReader reader = new BinaryReader(new FileStream(...));
int[] intArr = new int[reader.ReadInt32()];
byte[] byteArr = reader.ReadBytes(intArr.Length * sizeof(int));
Buffer.BlockCopy(byteArr, 0, intArr, 0, byteArr.Length);
Run Code Online (Sandbox Code Playgroud)
我决定将这一切都用于测试,使用10000个整数数组运行10000次测试.
这导致方法一在我的系统上平均消耗888200ns(约0.89ms).
虽然方法2在我的系统上平均消耗568600ns(平均0.57ms).
两次都包括垃圾收集器必须完成的工作.
显然,方法2比方法1快,但可能性较差.
方法1可能比方法2更好的另一个原因是,当处理有限的RAM /极大文件时,方法2需要的RAM数量比您要写入的数据(原始数据int[]和byte[]从中转换的数据)少两倍.int[](谈论512MB +),但如果是这种情况,你总是可以制作一个混合解决方案,例如一次写掉128MB.
请注意,方法1也需要这个额外的空间,但是由于它在每个项目的1个操作中被拆分int[],所以它可以更早地释放内存.
像这样的东西,一次写入128MB的一个int[]:
const int WRITECOUNT = 32 * 1024 * 1024; // 32 * sizeof(int)MB
int[] intArr = new int[140 * 1024 * 1024]; // 140 * sizeof(int)MB
for (int i = 0; i < intArr.Length; i++)
intArr[i] = i;
byte[] byteArr = new byte[WRITECOUNT * sizeof(int)]; // 128MB
int dataDone = 0;
using (Stream fileStream = new FileStream("data.dat", FileMode.Create))
using (BinaryWriter writer = new BinaryWriter(fileStream))
{
while (dataDone < intArr.Length)
{
int dataToWrite = intArr.Length - dataDone;
if (dataToWrite > WRITECOUNT) dataToWrite = WRITECOUNT;
Buffer.BlockCopy(intArr, dataDone, byteArr, 0, dataToWrite * sizeof(int));
writer.Write(byteArr);
dataDone += dataToWrite;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,这只是为了写作,阅读的工作方式也不同:P.我希望这能让你在处理非常大的数据文件方面有更多的见解:).
如果你只有一堆整数,那么在解析方面使用JSON确实效率很低.您可以有效地使用BinaryReader和BinaryWriter编写二进制文件...但是我不清楚为什么每次创建对象时都需要读取文件.为什么每个新对象都不能保留对已经读过一次的原始数组的引用?或者,如果他们需要改变数据,您可以保留一个"规范源",并在每次创建对象时将该数组复制到内存中.
从整数数组创建字节数组的最快方法是使用Buffer.BlockCopy
byte[] result = new byte[a.Length * sizeof(int)];
Buffer.BlockCopy(a, 0, result, 0, result.Length);
// write result to FileStream or wherever
Run Code Online (Sandbox Code Playgroud)
如果将数组的大小存储在第一个元素中,则可以再次使用它进行反序列化。确保所有内容都适合内存,但应查看文件大小。
var buffer = File.ReadAllBytes(@"...");
int size = BitConverter.ToInt32(buffer,0);
var result = new int[size];
Buffer.BlockCopy(buffer, 0, result, result.length);
Run Code Online (Sandbox Code Playgroud)
二进制不是人类可读的,但是绝对比JSON快。