[英]Fastest way to create files in C#
我正在運行一個程序來測試查找和迭代包含大量文件的文件夾中的所有文件的速度。 該過程中最慢的部分是創建100萬個文件。 我正在使用一種非常天真的方法來創建文件:
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);
輸出:
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)
如果有什么明顯比這更好的? 我想測試幾個數量級超過100萬的數量級,創建文件需要一天的時間!
我沒有嘗試任何類型的並行性,嘗試優化任何文件系統選項或更改文件創建的順序。
為了完整性,這里是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();
}
UPDATE
嘗試使用Parallel.For()
根據StriplingWarrior的建議進行Parallel.For()
。 結果:大約30個線程顛簸我的磁盤,網絡減速!
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.");
發現更改FileStream
的FileOptions
將性能提高約50%。 似乎我關閉了任何寫緩存。
new FileStream(filename, FileMode.CreateNew,
FileAccess.Write, FileShare.None,
4096, FileOptions.None)
結果:
Creating 10,000 file(s) of size 0 bytes... Done.
Time to CreateFiles: 12.390sec (8,071.05 files/sec, 1 in 1.2390ms)
其他想法仍然受歡迎。
你最大的瓶頸無疑是你的硬盤。 在一些快速測試中,我通過利用並行性能夠看到一些顯着的性能改進(但不是數量級):
Parallel.For(1, 10000,
i => File.Create(Path.Combine(path, i.ToString())));
有趣的是,至少在我的機器上,SSD似乎對此操作沒有太大影響。
我找到的最快的方法是圍繞File.Create()
的簡單循環:
IEnumerable filenames = GetFilenames();
foreach (var filename in filenames)
{
File.Create(filename);
}
這相當於(我在代碼中實際使用的內容):
IEnumerable filenames= GetFilenames();
foreach (var filename in filenames)
{
new FileStream(filename, FileMode.CreateNew,
FileAccess.Write, FileShare.None,
4096, FileOptions.None)
}
如果你真的想寫一些東西到文件:
IEnumerable filenames= GetFilenames();
foreach (var filename in filenames)
{
using (var fs = new FileStream(filename, FileMode.CreateNew,
FileAccess.Write, FileShare.None,
4096, FileOptions.None))
{
// Write something to your file.
}
}
似乎沒有幫助的事情:
Parallel.ForEach()
或Parallel.For()
形式的Parallel.ForEach()
。 這會產生凈減速,隨着線程數量的增加而變得更糟。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.