考虑到一个非常巨大的文件中(或许超过4G)的磁盘上,我要扫描通过这个文件和计算时间的一个具体的二元模式发生。

我想到的是:

  1. 使用存储器的映射文件(CreateFileMap 或提高mapped_file)载 文件的虚拟存储器。

  2. 对于每100MB映存,创建一个线扫描并计算的结果。

这是可行的?是否有任何更好的方法这样做吗?

更新:
存储器的映射文件将是一个好的选择,用于扫描通过1.6GB文件可能处理在11.

谢谢。

有帮助吗?

解决方案

多线程只会使这个转速度较慢,除非你要扫描的多个文件与每个不同的硬盘驱动器。否则你只是要求。

我写了一个简单的试验的功能使用的存储器映文件,用一个单一的线1.4Gb的文件了大约20秒钟的时间来扫描。有两个线程,每个把一半的文件(甚至1MB块到一个线程,奇怪的其他),它花了超过80秒。

  • 1线:20015毫秒
  • 2线程:83985毫秒

这是正确的,2线是 四个 时间慢于1线!

这里的代码,我在使用,这是单线版本,我使用了1字扫描图案,因此代码找到匹配跨越地图的边界是没有经过测试。

HRESULT ScanForPattern(LPCTSTR pszFilename, LPBYTE pbPattern, UINT cbPattern, LONGLONG * pcFound)
{
   HRESULT hr = S_OK;

   *pcFound = 0;
   if ( ! pbPattern || ! cbPattern)
      return E_INVALIDARG;

   //  Open the file
   //
   HANDLE hf = CreateFile(pszFilename,
                          GENERIC_READ,
                          FILE_SHARE_READ, NULL,
                          OPEN_EXISTING,
                          FILE_FLAG_SEQUENTIAL_SCAN,
                          NULL);

   if (INVALID_HANDLE_VALUE == hf)
      {
      hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
      // catch an open file that exists but is in use
      if (ERROR_SHARING_VIOLATION == GetLastError())
         hr = HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION);
      return hr;
      }

   // get the file length
   //
   ULARGE_INTEGER  uli;
   uli.LowPart = GetFileSize(hf, &uli.HighPart);
   LONGLONG cbFileSize = uli.QuadPart;
   if (0 == cbFileSize)
      {
      CloseHandle (hf);
      return S_OK;
      }

   const LONGLONG cbStride = 1 * 1024 * 1024; // 1 MB stride.
   LONGLONG cFound  = 0;
   LPBYTE   pbGap = (LPBYTE) malloc(cbPattern * 2);

   //  Create a mapping of the file.
   //
   HANDLE hmap = CreateFileMapping(hf, NULL, PAGE_READONLY, 0, 0, NULL);
   if (NULL != hmap)
      {
      for (LONGLONG ix = 0; ix < cbFileSize; ix += cbStride)
         {
         uli.QuadPart = ix;
         UINT cbMap = (UINT) min(cbFileSize - ix, cbStride);
         LPCBYTE pb = (LPCBYTE) MapViewOfFile(hmap, FILE_MAP_READ, uli.HighPart, uli.LowPart, cbMap);
         if ( ! pb)
            {
            hr = HRESULT_FROM_WIN32(GetLastError());
            break;
            }
         // handle pattern scanning over the gap.
         if (cbPattern > 1 && ix > 0)
            {
            CopyMemory(pbGap + cbPattern - 1, &pb[0], cbPattern - 1);
            for (UINT ii = 1; ii < cbPattern; ++ii)
               {
               if (pb[ii] == pbPattern[0] && 0 == memcmp(&pb[ii], pbPattern, cbPattern))
                  {
                  ++cFound; 
                  // advance by cbPattern-1 to avoid detecting overlapping patterns
                  }
               }
            }

         for (UINT ii = 0; ii < cbMap - cbPattern + 1; ++ii)
            {
            if (pb[ii] == pbPattern[0] && 
                ((cbPattern == 1) || 0 == memcmp(&pb[ii], pbPattern, cbPattern)))
               {
               ++cFound; 
               // advance by cbPattern-1 to avoid detecting overlapping patterns
               }
            }
         if (cbPattern > 1 && cbMap >= cbPattern)
            {
            // save end of the view in our gap buffer so we can detect map-straddling patterns
            CopyMemory(pbGap, &pb[cbMap - cbPattern + 1], cbPattern - 1);
            }
         UnmapViewOfFile(pb);
         }

      CloseHandle (hmap);
      }
   CloseHandle (hf);

   *pcFound = cFound;
   return hr;
}

其他提示

创建20线,每一假设处理一些100MB的文件可能只会恶化表现,因为高清将要读从几个不相关的地方在同一时间。

HD性能是在其高峰期时读的顺序数据。因此,假如你巨大的文件不是零散的,最好的事情要做会很可能只使用一个线程和阅读,从开始到结束,在大块的几(说4)MB。

但我怎么知道的。文件系统和缓存是复杂的。做一些测试看有什么效果最好。

虽然可以使用存储器的映射,你没有。如果你阅读该文件的顺序在小块,说1MB每,该文件将永远不会存在存储器的一次。

如果你搜索的代码实际上是慢于你的硬盘,你仍然可以手块关于工作人员的线如果你喜欢。

我会有一个纹读取文件(可能作为一个流)纳入一个阵列,并具有另外一个线程的过程。我不会地图数在同一时间,因为磁盘的目的。我可能会有一个ManualResetEvent告诉我的螺纹当下?字节是准备进行处理。假设你进程代码是那么快的硬盘我想有2个缓冲区,一个以填补和其他进程和它们之间只是切换,每次。

我想去只有一个螺纹也一样,不仅用于高清业绩问题,而是因为你可能有麻烦管理的副作用,当分裂的文件:什么如果有一个出现图案就在你分割你的文件?

使用的存储器映文件具有额外的好处是避免了一个复制文件系统的高速缓冲存储器的(管理)应用程序的记忆,如果您使用的只读查(虽然你必须使用byte*指针,然后访问的存储器)。而不是创造了许多线程,使用一个线程的顺序通过扫描文件使用的例如100MB存储器映意见纳入本文件(不映整个文件成为该进程的地址的空间,在一次)。

蒂姆布雷(和他的读者)探索这个深度他 广泛的搜索项目广泛的搜索2. 基准测试结果 表明,多线程的实现方式可以超越单线解决方案 在一个巨大的太阳核的服务器.在通常的电脑硬件,多线程不会得到你那么多,如果在所有。

我会做到这一步读到一个双缓冲器。因此,当一个缓冲区,已经从中读取文件,开始阅读下一个缓冲区的同时,扫描的第一个缓冲区。这意味着你做CPU和IO行。另一个优点是,你总是会有的数据围绕数据的界限。但是我不知道,如果双缓冲能够与存储器映的文件。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top