Pregunta

Teniendo en cuenta un archivo muy grande (tal vez más de 4 GB) en el disco, quiero explorar a través de este archivo y calcular los tiempos de un determinado patrón binario se produce.

Mi pensamiento es:

  1. Usar archivo asignado en memoria (CreateFileMap o impulso mapped_file) para cargar el archivo a la memoria virtual.

  2. Para cada 100 MB mapeada-memoria, crear un hilo para escanear y calcular el resultado.

Hay esta factible? ¿Alguno mejor método para hacerlo?

Actualizar :
archivo asignado en memoria sería una opción buena, por escaneando a través de un archivo de 1,6 GB podría ser manejado dentro de 11s.

gracias.

¿Fue útil?

Solución

multihilo sólo va a hacer este movimiento lento a menos que desee escanear archivos múltiples con cada uno en un disco duro diferente. De lo contrario sólo se va a buscar.

Me escribió una función de prueba simple usando archivos de memoria asignada, con un único hilo de un archivo de 1,4 GB tomó alrededor de 20 segundos para escanear. Con dos hilos, cada uno teniendo un medio el archivo (incluso de 1 MB trozos a un hilo, impar a la otra), se tardó más de 80 segundos.

  • 1 hilo: 20015 milisegundos
  • 2 hilos: 83985 milisegundos

Así es, 2 hilos fue Cuatro veces más lento que 1 hilo!

Este es el código que usé, esta es la versión de un solo subproceso, he usado un patrón de lectura de 1 byte, por lo que el código para localizar coincidencias que las fronteras mapa de pórtico no se ha probado.

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;
}

Otros consejos

La creación de 20 hilos, cada uno pensando que manejar unos 100 MB del archivo es probable que el rendimiento sólo empeorará Desde entonces, el HD tendrá que leer desde varios lugares no relacionados al mismo tiempo.

rendimiento de alta definición está en su apogeo cuando lee los datos secuenciales. Así que asumiendo que su enorme archivo no está fragmentada, lo mejor que puede hacer probablemente sería utilizar un solo hilo y leer de principio a fin en trozos de unos pocos (digamos 4) MB.

Pero, ¿qué sé yo. Los sistemas de archivos y cachés son complejas. Hacer algunas pruebas y ver lo que funciona mejor.

A pesar de que se puede utilizar la asignación de memoria, usted no tiene que hacerlo. Si usted lee el archivo secuencialmente en trozos pequeños, digamos 1 MB cada uno, el archivo no estará presente en la memoria a la vez.

Si su código de búsqueda es en realidad más lento que su disco duro, puede todavía trozos de mano de subprocesos de trabajo si te gusta.

I tendría un hilo leer el archivo (posiblemente como una corriente) en una matriz y tener otro proceso hilo él. Me volvería a hacer que varias a la vez, debido a búsquedas en disco. Probablemente tendría un ManualResetEvent para contar mi hilo cuando el próximo? bytes están listos para ser procesado. Asumiendo que su código de proceso es más rápido que el disco duro me gustaría tener 2 tampones, uno para llenar y el otro al proceso y simplemente cambiar entre ellos cada vez.

Me gustaría ir con sólo un hilo demasiado, no sólo para los problemas de rendimiento de alta definición, sino porque es posible que tenga efectos secundarios gestión de problemas cuando se divide el archivo:? ¿Y si hay una aparición de su patrón justo donde se divide el archivo

El uso de un archivo de memoria asignada tiene el beneficio adicional de evitar una copia de la memoria caché del sistema de archivos de la memoria del dispositivo (administrado) Si utiliza una vista de sólo lectura (aunque usted tiene que utilizar el byte * punteros a continuación para acceder a la memoria ). Y en vez de crear muchos hilos utilizan un hilo de forma secuencial a través de la exploración de archivos utilizando, por ejemplo vistas mapeadas de memoria de 100 MB en el archivo (no se asignan todo el archivo en el espacio de direcciones del proceso a la vez).

scroll top