如何尽可能高效地处理大量并发磁盘写请求

Can*_*rse 9 .net c# disk

假设下面的方法被.net 4应用程序中的不同线程调用了几千次.处理这种情况的最佳方法是什么?了解磁盘是这里的瓶颈,但我希望WriteFile()方法快速返回.

数据可以高达几MB.我们在谈论线程池,TPL等吗?

public void WriteFile(string FileName, MemoryStream Data)
{
   try
   {
      using (FileStream DiskFile = File.OpenWrite(FileName))
      {
         Data.WriteTo(DiskFile);
         DiskFile.Flush();
         DiskFile.Close();
      }
   }
   catch (Exception e)
   {
      Console.WriteLine(e.Message);
   }
}
Run Code Online (Sandbox Code Playgroud)

Val*_*zub 6

如果你想快速返回而不是真的关心操作是同步的,那么你可以在内存Queue中创建某种类型的写入请求,而当Queue没有填满时你可以快速从方法返回.另一个线程将负责调度Queue和写入文件.如果你WriteFile被调用并且队列已满,你将不得不等到你可以排队并且执行将再次变为同步,但是这样你可以有一个大的缓冲区,所以如果进程文件写请求不是线性的,而是更尖刻的(与写入文件调用之间的暂停峰值)这种变化可以看作是对性能的改进.

更新: 为你做一个小图片.请注意,瓶颈始终存在,您可以做的就是使用队列优化请求.请注意,队列有限制,所以当它填满时,你不能将文件队列成inst,你必须等待,因此该缓冲区中也有一个空闲空间.但是对于图片中呈现的情况(3个桶请求),显而易见的是,您可以快速将桶放入队列并返回,而在第一种情况下,您必须逐个执行此操作并阻止执行.

请注意,您永远不需要同时执行多个IO线程,因为它们都将使用相同的瓶颈,如果您尝试并行处理这个问题就会浪费内存,我相信2到10个线程顶部将轻松占用所有可用的IO带宽,也将限制应用程序内存使用量.

在此输入图像描述

  • 好吧,这就是为什么您需要在返回之前检查队列是否已满。设置队列的最大大小,并检查队列的填充是否小于该大小。如果您的写入速度为 10mb 秒,并且传入的请求非常高,以至于您需要 1GB 秒来存储它们,那么如果不进行重大硬件更改,您就无能为力。 (2认同)
  • 谢谢你的精美图表. (2认同)

Cam*_*ron 3

既然您说文件不需要按顺序写入,也不需要立即写入,那么最简单的方法是使用Task

private void WriteFileAsynchronously(string FileName, MemoryStream Data)
{
    Task.Factory.StartNew(() => WriteFileSynchronously(FileName, Data));
}

private void WriteFileSynchronously(string FileName, MemoryStream Data)
{
    try
    {
        using (FileStream DiskFile = File.OpenWrite(FileName))
        {
            Data.WriteTo(DiskFile);
            DiskFile.Flush();
            DiskFile.Close();
        }
    }

    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }
}
Run Code Online (Sandbox Code Playgroud)

TPL 在内部使用线程池,即使对于大量任务也应该相当高效。