2011-09-08 10 views
10

Tengo 3 * archivos .dat (346KB, 725KB, 1762KB) que están llenos con una json-cadena de "grandes" int-Arrays.Mejor/más rápida forma de llenar una gran matriz en C#

Cada vez que se crea mi objeto (varias veces) tomo esos tres archivos y uso JsonConvert.DeserializeObject para deserializar las matrices en el objeto.

Pensé en usar archivos binarios en lugar de json-string o incluso podría guardar estas matrices directamente? No necesito usar estos archivos, es solo la ubicación donde se guardan los datos. Con gusto cambiaría a algo más rápido.

¿Cuáles son las diferentes maneras de acelerar la inicialización de estos objetos?

+3

No está muy claro para mí lo que está pidiendo, ¿podría mostrarnos su código actual y luego podemos tratar de encontrar la manera de mejorarlo? –

+0

¿Cómo se almacenan los datos exactamente? Una línea por conjunto? – VMAtm

+0

@JonSkeet ¿Está más claro ahora? – Sven

Respuesta

9

La manera más rápida es serializar manualmente los datos.

Una manera fácil de hacerlo es creando un FileStream, y luego envolverlo en un BinaryWriter/BinaryReader.

Usted tiene acceso a las funciones de escribir las estructuras de datos básicos (numbers, string, char, byte[] y char[]).

Una manera fácil de escribir un int[] (innecesario si es de tamaño fijo) es anteponiendo la longitud de la matriz con un int/largo (dependiendo del tamaño, sin signo no ofrece ninguna ventaja, ya que las matrices usan tipos de datos firmados para su almacenamiento de longitud). Y luego escribe todos los enteros.

Dos maneras de escribir todas las entradas sería:
1. Simplemente recorra toda la matriz.
2. Convertir en un byte[] y escribir usando BinaryWriter.Write(byte[])

Estos es cómo se puede aplicar a los dos:

// 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); 

decidí poner todo esto a la prueba, con una serie de números enteros 10000 Ejecuté la prueba 10000 veces.

Resultó que el método uno consume un promedio de 888200ns en mi sistema (aproximadamente 0.89ms).
Mientras que el método 2 solo consume un promedio de 568600ns en mi sistema (0.57ms en promedio).

Ambos tiempos incluyen el trabajo que el recolector de basura tiene que hacer.

Obviamente, el método 2 es más rápido que el método 1, aunque posiblemente menos legible.

Otra razón por la cual el método 1 puede ser mejor que el método 2 se debe a que el método 2 requiere el doble de la cantidad de memoria RAM libre que los datos que vas a escribir (el original int[] y la byte[] que se convierte de la int[]), cuando se trata de con RAM limitada/archivos extremadamente grandes (hablando de 512MB +), aunque si este es el caso, siempre puede hacer una solución híbrida, por ejemplo, grabando 128 MB a la vez.

Tenga en cuenta que el método 1 también requiere este espacio adicional, pero debido a que está dividido en 1 operación por elemento del int[], puede liberar la memoria mucho antes.

Algo como esto, escribirá 128MB de una int[] a la vez:

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; 
    } 
} 

Tenga en cuenta que esto es sólo para la escritura, la lectura de las obras de manera diferente también: P. Espero que esto te brinde más información al tratar con archivos de datos muy grandes :).

6

Si acaba de obtener muchos enteros, el uso de JSON será bastante ineficiente en términos de análisis. Puede usar BinaryReader y BinaryWriter para escribir archivos binarios de manera eficiente ... pero no tengo claro por qué necesita leer el archivo cada vez que crea un objeto de todos modos. ¿Por qué no puede cada objeto nuevo mantener una referencia a la matriz original, que se ha leído una vez? O si necesitan mutar los datos, puede mantener una "fuente canónica" y simplemente copiar esa matriz en la memoria cada vez que cree un objeto.

+0

+1 por "¿Por qué no puede cada objeto nuevo mantener una referencia a la matriz original" –

4

La forma más rápida de crear una matriz de bytes a partir de una matriz de enteros es usar Buffer.BlockCopy

byte[] result = new byte[a.Length * sizeof(int)]; 
Buffer.BlockCopy(a, 0, result, 0, result.Length); 
// write result to FileStream or wherever 

Si almacena el tamaño de la matriz en el primer elemento, se puede volver a usar para deserializar . Asegúrese de que todo encaja en la memoria, pero mirando los tamaños de archivo que debería.

var buffer = File.ReadAllBytes(@"..."); 
int size = BitConverter.ToInt32(buffer,0); 
var result = new int[size]; 
Buffer.BlockCopy(buffer, 0, result, result.length); 

Binario no es legible para humanos, pero definitivamente más rápido que JSON.

Cuestiones relacionadas