【问题标题】:How to Perform Asynchronous File Reads in C# 2.0?如何在 C# 2.0 中执行异步文件读取?
【发布时间】:2009-04-29 02:04:07
【问题描述】:

我有一个应用程序需要遍历文本文件中的所有行,大小超过千兆字节。其中一些文件有 10 或 100 的数百万行。

我当前(和同步)阅读的一个例子,看起来像......

  using (FileStream stream = new FileStream(args[0], FileMode.Open, FileAccess.Read, FileShare.Read)) {
    using (StreamReader streamReader = new StreamReader(stream)) {
      string line;
      while (!string.IsNullOrEmpty(line = streamReader.ReadLine())) {           
        //do stuff with the line string...
      }
    }
  }

我已经阅读了一些关于 .Net 异步 IO 流式传输方法的资料,我正在寻求有关此问题的 2 个具体问题的帮助。

首先,如果我需要每一行的整体性,我会通过异步读取这些文件来提高性能,这些文件通常很短,但长度不同(文件中的每一行之间没有关系)?

其次,如何将上面的代码转换为异步读取,以便像现在一样逐行处理每一行?

【问题讨论】:

    标签: .net multithreading file-io c#-2.0


    【解决方案1】:

    您可以尝试使文件读取异步,而不是使该行读取异步。这就是将您问题中的所有代码都包含在一个工作人员委托中。

        static void Main(string[] args)
        {
            WorkerDelegate worker = new WorkerDelegate(Worker);
            // Used for thread and result management.
            List<IAsyncResult> results = new List<IAsyncResult>();
            List<WaitHandle> waitHandles = new List<WaitHandle>();
    
            foreach (string file in Directory.GetFiles(args[0], "*.txt"))
            {
                // Start a new thread.
                IAsyncResult res = worker.BeginInvoke(file, null, null);
                // Store the IAsyncResult for that thread.
                results.Add(res);
                // Store the wait handle.
                waitHandles.Add(res.AsyncWaitHandle);
            }
    
            // Wait for all the threads to complete.
            WaitHandle.WaitAll(waitHandles.ToArray(), -1, false); // for < .Net 2.0 SP1 Compatibility
    
            // Gather all the results.
            foreach (IAsyncResult res in results)
            {
                try
                {
                    worker.EndInvoke(res);
                    // object result = worker.EndInvoke(res); // For a worker with a result.
                }
                catch (Exception ex)
                {
                    // Something happened in the thread.
                }
            }
        }
    
        delegate void WorkerDelegate(string fileName);
        static void Worker(string fileName)
        {
            // Your code.
            using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                using (StreamReader streamReader = new StreamReader(stream))
                {
                    string line;
                    while (!string.IsNullOrEmpty(line = streamReader.ReadLine()))
                    {
                        //do stuff with the line string...
                    }
                }
            }
        }
    

    【讨论】:

    • 这段代码很完美。我会为异步文件读取做同样的事情。
    • 我同意。这很甜蜜。只是在尝试为同一问题设计不同的解决方案时为我节省了很多工作。
    【解决方案2】:

    异步模式是 BeginRead()/EndRead()。

    您是否获得提升在很大程度上取决于您进行阅读时发生的其他情况。在等待读取时,您的应用程序还能做些什么吗?如果没有,那么异步将无济于事......

    【讨论】:

    • 是的,我已经读过,但 BeginRead() 不是仅读取缓冲区的字节长度吗?那不是要返回每一行,是吗?还是我弄错了?
    【解决方案3】:

    异步读取最终只会使每个块的磁头寻找更多。通过对文件系统上的文件进行良好的碎片整理并使用同步读取,您将获得更好的性能提升。

    正如已经指出的那样,将行处理分派给其他线程应该会带来提升(尤其是在多核 CPU 上)

    【讨论】:

      【解决方案4】:

      如果性能非常关键,我建议调查FILE_FLAG_SEQUENTIAL_SCAN 的互操作性,请参阅details here

      最好还是编写一个小型 C++ 应用程序,在打开该标志的情况下扫描文件,看看它是否能提高性能。

      【讨论】:

        猜你喜欢
        • 2018-04-29
        • 1970-01-01
        • 2020-08-20
        • 2012-12-07
        • 1970-01-01
        • 2014-08-08
        • 2018-11-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多