Bueno, hice una pequeña prueba y definitivamente recomendaría usar archivos asignados de memoria. Creé un archivo que contiene 350M de valores dobles (2.6 GB como se mencionó anteriormente) y luego probé el tiempo que toma para asignar el archivo a la memoria y luego acceder a cualquiera de los elementos.
En todas mis pruebas en mi computadora portátil (Win7, .Net 4.0, Core2 Duo 2.0 GHz, 4GB de RAM) tardé menos de un segundo en mapear el archivo y en ese momento acceder a cualquiera de los elementos tomó prácticamente 0ms (todos el tiempo está en la validación del índice). Luego, decidí revisar todos los números de 350M y todo el proceso tomó aproximadamente 3 minutos (se incluyeron los mensajes de paginación), por lo que si en su caso tiene que iterar, puede ser otra opción.
Sin embargo, me envolvió el acceso, sólo para propósitos de ejemplo allí unas condiciones mucho que se debe comprobar antes de utilizar este código, y parece que este
public class Storage<T> : IDisposable, IEnumerable<T> where T : struct
{
MemoryMappedFile mappedFile;
MemoryMappedViewAccessor accesor;
long elementSize;
long numberOfElements;
public Storage(string filePath)
{
if (string.IsNullOrWhiteSpace(filePath))
{
throw new ArgumentNullException();
}
if (!File.Exists(filePath))
{
throw new FileNotFoundException();
}
FileInfo info = new FileInfo(filePath);
mappedFile = MemoryMappedFile.CreateFromFile(filePath);
accesor = mappedFile.CreateViewAccessor(0, info.Length);
elementSize = Marshal.SizeOf(typeof(T));
numberOfElements = info.Length/elementSize;
}
public long Length
{
get
{
return numberOfElements;
}
}
public T this[long index]
{
get
{
if (index < 0 || index > numberOfElements)
{
throw new ArgumentOutOfRangeException();
}
T value = default(T);
accesor.Read<T>(index * elementSize, out value);
return value;
}
}
public void Dispose()
{
if (accesor != null)
{
accesor.Dispose();
accesor = null;
}
if (mappedFile != null)
{
mappedFile.Dispose();
mappedFile = null;
}
}
public IEnumerator<T> GetEnumerator()
{
T value;
for (int index = 0; index < numberOfElements; index++)
{
value = default(T);
accesor.Read<T>(index * elementSize, out value);
yield return value;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
T value;
for (int index = 0; index < numberOfElements; index++)
{
value = default(T);
accesor.Read<T>(index * elementSize, out value);
yield return value;
}
}
public static T[] GetArray(string filePath)
{
T[] elements;
int elementSize;
long numberOfElements;
if (string.IsNullOrWhiteSpace(filePath))
{
throw new ArgumentNullException();
}
if (!File.Exists(filePath))
{
throw new FileNotFoundException();
}
FileInfo info = new FileInfo(filePath);
using (MemoryMappedFile mappedFile = MemoryMappedFile.CreateFromFile(filePath))
{
using(MemoryMappedViewAccessor accesor = mappedFile.CreateViewAccessor(0, info.Length))
{
elementSize = Marshal.SizeOf(typeof(T));
numberOfElements = info.Length/elementSize;
elements = new T[numberOfElements];
if (numberOfElements > int.MaxValue)
{
//you will need to split the array
}
else
{
accesor.ReadArray<T>(0, elements, 0, (int)numberOfElements);
}
}
}
return elements;
}
}
Aquí está un ejemplo de cómo se puede utilizar la clase
Stopwatch watch = Stopwatch.StartNew();
using (Storage<double> helper = new Storage<double>("Storage.bin"))
{
Console.WriteLine("Initialization Time: {0}", watch.ElapsedMilliseconds);
string item;
long index;
Console.Write("Item to show: ");
while (!string.IsNullOrWhiteSpace((item = Console.ReadLine())))
{
if (long.TryParse(item, out index) && index >= 0 && index < helper.Length)
{
watch.Reset();
watch.Start();
double value = helper[index];
Console.WriteLine("Access Time: {0}", watch.ElapsedMilliseconds);
Console.WriteLine("Item: {0}", value);
}
else
{
Console.Write("Invalid index");
}
Console.Write("Item to show: ");
}
}
ACTUALIZACIÓN I añadió un método estático para cargar todos los datos en un archivo a una matriz. Obviamente, este enfoque lleva más tiempo inicialmente (en mi computadora portátil tarda entre 1 y 2 minutos) pero después de eso, el rendimiento de acceso es lo que espera de .Net. Este método debería ser útil si tiene que acceder a los datos con frecuencia.
uso es bastante simple
double[] helper = Storage<double>.GetArray("Storage.bin");
HTH
+1 para wow factor – northpole
No veo por qué tendrías que dividir en varios archivos. Usted sabe cuántas líneas hay (suponiendo 1 número/línea), por lo que puede hacer que diferentes hilos comiencen a leer el archivo en diferentes desplazamientos. – FrustratedWithFormsDesigner
¿No es esto como 2.6 gigas de datos? –