如何优化C#并发文件写入性能
How to optimize C# concurrent file write performance
我正在尝试优化将大量小文件创建到 SSD 磁盘的性能。
ConcurrentBag<string[]> cb = new ConcurrentBag<string[]>();
cb.AsParallel().ForAll(fa => File.WriteAllText(fa[0], fa[1]));
ConcurrentBag<string[]>
的总计数 = 80048,cb.Sum(gbc => Encoding.UTF8.GetByteCount( gbc[1] ) );
returns 393441217 字节。
我在其他地方做了一个 xml.Save();
,它创建了一个大约 750MB 的文件。
第一种情况需要 3 分 30 秒才能完成。第二个20秒。
我知道处理所有单独的写入操作会产生一些开销,但 3 分 30 秒似乎仍然有点长。我已经尝试使用 forall 进行并行化,这非常有用(之前需要 6-8 分钟才能完成)。我可以向我的代码添加哪些其他修改来优化批量文件创建的性能?
实际上,同时进行多个 IO 操作会大大降低速度,尤其是在传统磁盘上。我建议使用 ConcurrentQueue
来写入多个文件。
您也可以切换到 StreamWriter
并控制缓冲区大小以提高写入速度:
ConcurrentQueue<string[]> concurrentQueue = new ConcurrentQueue<string[]>();
// populate with some data
for (int i = 0; i < 5000; i++)
{
concurrentQueue.Enqueue(new string[] { Guid.NewGuid().ToString(), Guid.NewGuid().ToString() });
}
while (true)
{
string[] currentElement;
bool success = concurrentQueue.TryDequeue(out currentElement);
if (success)
{
const int BufferSize = 65536; // change it to your needs
using (var sw = new StreamWriter(currentElement[0], true, Encoding.UTF8, BufferSize))
{
sw.Write(currentElement[1]);
}
}
}
您还应该尝试使用 ForEach 而不是 ForAll。
你可以在 post http://reedcopsey.com/2010/02/03/parallelism-in-net-part-8-plinqs-forall-method/
中找到一些很好的理由
post 准则是
The ForAll extension method should only be used to process the
results of a parallel query, as returned by a PLINQ expression
我正在尝试优化将大量小文件创建到 SSD 磁盘的性能。
ConcurrentBag<string[]> cb = new ConcurrentBag<string[]>();
cb.AsParallel().ForAll(fa => File.WriteAllText(fa[0], fa[1]));
ConcurrentBag<string[]>
的总计数 = 80048,cb.Sum(gbc => Encoding.UTF8.GetByteCount( gbc[1] ) );
returns 393441217 字节。
我在其他地方做了一个 xml.Save();
,它创建了一个大约 750MB 的文件。
第一种情况需要 3 分 30 秒才能完成。第二个20秒。
我知道处理所有单独的写入操作会产生一些开销,但 3 分 30 秒似乎仍然有点长。我已经尝试使用 forall 进行并行化,这非常有用(之前需要 6-8 分钟才能完成)。我可以向我的代码添加哪些其他修改来优化批量文件创建的性能?
实际上,同时进行多个 IO 操作会大大降低速度,尤其是在传统磁盘上。我建议使用 ConcurrentQueue
来写入多个文件。
您也可以切换到 StreamWriter
并控制缓冲区大小以提高写入速度:
ConcurrentQueue<string[]> concurrentQueue = new ConcurrentQueue<string[]>();
// populate with some data
for (int i = 0; i < 5000; i++)
{
concurrentQueue.Enqueue(new string[] { Guid.NewGuid().ToString(), Guid.NewGuid().ToString() });
}
while (true)
{
string[] currentElement;
bool success = concurrentQueue.TryDequeue(out currentElement);
if (success)
{
const int BufferSize = 65536; // change it to your needs
using (var sw = new StreamWriter(currentElement[0], true, Encoding.UTF8, BufferSize))
{
sw.Write(currentElement[1]);
}
}
}
您还应该尝试使用 ForEach 而不是 ForAll。 你可以在 post http://reedcopsey.com/2010/02/03/parallelism-in-net-part-8-plinqs-forall-method/
中找到一些很好的理由post 准则是
The ForAll extension method should only be used to process the results of a parallel query, as returned by a PLINQ expression