visual tutorial programacion primera paginas pagina net ejemplos ejemplo crear asp asax aplicaciones aplicacion asp.net multithreading web-applications caching file-io

asp.net - tutorial - pagina web asp net c#



Estrategia de acceso a archivos en un entorno multiproceso(aplicaciĆ³n web) (5)

Tengo un archivo que es una representación XML de algunos datos tomados de un servicio web y almacenados en caché localmente dentro de una aplicación web. La idea es que esta información es muy estática, pero podría cambiar. Así que lo configuré para almacenar en caché un archivo y pegué un monitor contra él para verificar si se eliminó. Una vez eliminado, el archivo se actualizará desde su fuente y se reconstruirá.

Ahora estoy corriendo hacia los problemas, porque obviamente en un entorno de subprocesos múltiples se cae al intentar acceder a los datos cuando todavía está leyendo / escribiendo el archivo.

Esto me confunde, porque agregué un objeto para bloquear, y esto siempre está bloqueado durante la lectura / escritura. Según tengo entendido, se le dijo al intento de acceso desde otros hilos que "espere" hasta que se libere el bloqueo.

Solo para que sepas, soy realmente nuevo en el desarrollo de subprocesos múltiples, por lo que estoy totalmente dispuesto a aceptar que esto es un error de mi parte :)

  • ¿Me estoy perdiendo de algo?
  • ¿Cuál es la mejor estrategia de acceso a archivos en un entorno de subprocesos múltiples?

Editar

Lo siento, debería haber dicho que esto es usando ASP.NET 2.0 :)


¿Qué le AutoResetEvent usar AutoResetEvent para comunicarse entre hilos? createfile una aplicación de consola que crea aproximadamente 8 GB de archivo en el método createfile y luego copio ese archivo en el método main

static AutoResetEvent waitHandle = new AutoResetEvent(false); static string filePath=@"C:/Temp/test.txt"; static string fileCopyPath=@"C:/Temp/test-copy.txt"; static void Main(string[] args) { Console.WriteLine("in main method"); Console.WriteLine(); Thread thread = new Thread(createFile); thread.Start(); Console.WriteLine("waiting for file to be processed "); Console.WriteLine(); waitHandle.WaitOne(); Console.WriteLine(); File.Copy(filePath, fileCopyPath); Console.WriteLine("file copied "); } static void createFile() { FileStream fs= File.Create(filePath); Console.WriteLine("start processing a file "+DateTime.Now); Console.WriteLine(); using (StreamWriter sw = new StreamWriter(fs)) { for (long i = 0; i < 300000000; i++) { sw.WriteLine("The value of i is " + i); } } Console.WriteLine("file processed " + DateTime.Now); Console.WriteLine(); waitHandle.Set(); }


Aquí está el código que uso para asegurarme de que un archivo no esté bloqueado por otro proceso. No es 100% infalible, pero hace el trabajo la mayor parte del tiempo:

/// <summary> /// Blocks until the file is not locked any more. /// </summary> /// <param name="fullPath"></param> bool WaitForFile(string fullPath) { int numTries = 0; while (true) { ++numTries; try { // Attempt to open the file exclusively. using (FileStream fs = new FileStream(fullPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None, 100)) { fs.ReadByte(); // If we got this far the file is ready break; } } catch (Exception ex) { Log.LogWarning( "WaitForFile {0} failed to get an exclusive lock: {1}", fullPath, ex.ToString()); if (numTries > 10) { Log.LogWarning( "WaitForFile {0} giving up after 10 tries", fullPath); return false; } // Wait for the lock to be released System.Threading.Thread.Sleep(500); } } Log.LogTrace("WaitForFile {0} returning true after {1} tries", fullPath, numTries); return true; }

Obviamente, puede ajustar los tiempos de espera y reintentos para adaptarse a su aplicación. Lo uso para procesar grandes archivos FTP que tardan un tiempo en escribirse.


OK, he estado trabajando en esto y terminé creando un módulo de prueba de estrés para básicamente eliminar la mierda de mi código a partir de varios hilos ( ver la pregunta relacionada ).

Desde este punto, fue mucho más fácil encontrar agujeros en mi código. Resulta que mi código no estaba realmente lejos, pero había una cierta ruta lógica en la que podía entrar, lo que básicamente causaba que las operaciones de lectura / escritura se acumularan, lo que significaba que si no se eliminaban a tiempo, lo haría ¡vete, boom!

Una vez que lo saqué, realicé nuevamente mi prueba de estrés, ¡todo funcionó bien!

Por lo tanto, realmente no hice nada especial en mi código de acceso a archivos, simplemente me aseguré de usar sentencias de lock cuando correspondía (es decir, cuando leía o escribía).


Si está bloqueando un objeto almacenado como estático, entonces el bloqueo debería funcionar para todos los hilos en el mismo Dominio de aplicación, pero tal vez necesite cargar una muestra de código para que podamos echarle un vistazo a las líneas ofensivas.

Dicho eso, una idea sería verificar si IIS está configurado para ejecutarse en modo Web Garden (es decir, más de 1 proceso ejecutando su aplicación), lo que rompería su lógica de bloqueo. Si bien podría solucionar esa situación con un mutex, sería más fácil reconfigurar su aplicación para ejecutarla en un solo proceso, aunque sería bueno que verifique el rendimiento antes y después de jugar con la configuración del jardín web ya que puede afectarlo. actuación.


Tal vez puedas crear el archivo con un nombre temporal ("data.xml_TMP"), y cuando esté listo, cambiar el nombre a lo que se supone que debe ser. De esta forma, ningún otro proceso accederá antes de que esté listo.