Estoy ejecutando un programa para comparar qué tan rápido encontrar e iterar sobre todos los archivos en una carpeta con un gran número de archivos. La parte más lenta del proceso es crear el millón de archivos más. Estoy usando un método bastante ingenua para crear los archivos en la actualidadLa forma más rápida de crear archivos en C#
Console.Write("Creating {0:N0} file(s) of size {1:N0} bytes... ",
options.FileCount, options.FileSize);
var createTimer = Stopwatch.StartNew();
var fileNames = new List<string>();
for (long i = 0; i < options.FileCount; i++)
{
var filename = Path.Combine(options.Directory.FullName,
CreateFilename(i, options.FileCount));
using (var file = new FileStream(filename, FileMode.CreateNew,
FileAccess.Write, FileShare.None, 4096,
FileOptions.WriteThrough))
{
// I have an option to write some data to files, but it's not being used.
// That's why there's a using here.
}
fileNames.Add(filename);
}
createTimer.Stop();
Console.WriteLine("Done.");
// Other code appears here.....
Console.WriteLine("Time to CreateFiles: {0:N3}sec ({1:N2} files/sec, 1 in {2:N4}ms)"
, createTimer.Elapsed.TotalSeconds
, (double)total/createTimer.Elapsed.TotalSeconds
, createTimer.Elapsed.TotalMilliseconds/(double)options.FileCount);
Salida:
Creating 1,000,000 file(s) of size 0 bytes... Done.
Time to CreateFiles: 9,182.283sec (1,089.05 files/sec, 1 in 9.1823ms)
Si hay algo obviamente mejor que esto? Estoy buscando para probar varios órdenes de magnitud superior a 1 millón, y se necesita un día para crear los archivos!
No he probado ningún tipo de paralelismo, tratando de optimizar cualquier opción de sistema de archivos o cambiando el orden de creación de archivos.
Para completar, aquí está el contenido de CreateFilename()
:
public static string CreateFilename(long i, long totalFiles)
{
if (totalFiles < 0)
throw new ArgumentOutOfRangeException("totalFiles",
totalFiles, "totalFiles must be positive");
// This tries to keep filenames to the 8.3 format as much as possible.
if (totalFiles < 99999999)
// No extension.
return String.Format("{0:00000000}", i);
else if (totalFiles >= 100000000 && totalFiles < 9999999999)
{
// Extend numbers into extension.
long rem = 0;
long div = Math.DivRem(i, 1000, out rem);
return String.Format("{0:00000000}", div) + "." +
String.Format("{0:000}", rem);
}
else
// Doesn't fit in 8.3, so just tostring the long.
return i.ToString();
}
ACTUALIZACIÓN
Intentó paralelizar según la sugerencia de StriplingWarrior usando Parallel.For()
. Resultados: alrededor de 30 hilos golpeando mi disco y una red más lenta!
var fileNames = new ConcurrentBag<string>();
var opts = new ParallelOptions();
opts.MaxDegreeOfParallelism = 1; // 1 thread turns out to be fastest.
Parallel.For(0L, options.FileCount, opts,
() => new { Files = new List<string>() },
(i, parState, state) =>
{
var filename = Path.Combine(options.Directory.FullName,
CreateFilename(i, options.FileCount));
using (var file = new FileStream(filename, FileMode.CreateNew
, FileAccess.Write, FileShare.None
, 4096, FileOptions.WriteThrough))
{
}
fileNames.Add(filename);
return state;
},
state =>
{
foreach (var f in state.Files)
{
fileNames.Add(f);
}
});
createTimer.Stop();
Console.WriteLine("Done.");
encontrado que el cambio de la FileOptions
en el FileStream
mejorado perf por ~ 50%. Parece que estaba apagando cualquier caché de escritura.
new FileStream(filename, FileMode.CreateNew,
FileAccess.Write, FileShare.None,
4096, FileOptions.None)
Resultados:
Creating 10,000 file(s) of size 0 bytes... Done.
Time to CreateFiles: 12.390sec (8,071.05 files/sec, 1 in 1.2390ms)
Otras ideas todavía dan la bienvenida.
¿Tiene que escribirlos todos en un único directorio? Si puedes dividirlo para decir 1000 archivos en 1000 directorios, las cosas pueden ser más rápidas. – Oded
¿Qué hay de usar C? Por cierto, creo que habrá limitaciones si usa HDD. SSD puede ayudar a acelerar las cosas un poco. – user482594
Por lo que vale, este es casi seguro un límite de su disco/sistema de archivos particular, no C#. La solución SSD ayudaría, con seguridad. –