2010-04-29 15 views
8

Soy nuevo en el roscado y quiere hacer algo similar a esta pregunta:El uso de múltiples hilos de bucle

Speed up loop using multithreading in C# (Question)

Sin embargo, no estoy seguro de si esa solución es la mejor para mí, como yo quiero que sigan corriendo y nunca terminen. (También estoy usando .NET 3.5 en lugar de 2.0 como para esa pregunta.)

quiero hacer algo como esto:

foreach (Agent agent in AgentList) 
{ 
    // I want to start a new thread for each of these 
    agent.DoProcessLoop(); 
} 

--- 

public void DoProcessLoop() 
{ 
    while (true) 
    { 
     // do the processing 

     // this is things like check folder for new files, update database 
     // if new files found 
    } 
} 

¿Un ThreadPool ser la mejor solución o hay algo que se adapte ¿esto mejor?

Actualización: ¡Gracias por todas las buenas respuestas! Pensé en explicar el caso de uso con más detalle. Varios agentes pueden subir archivos a una carpeta. Cada agente tiene su propia carpeta a la que pueden cargar activos (archivos csv, imágenes, pdfs). Nuestro servicio (se supone que es un servicio de Windows que se ejecuta en el servidor al que cargan sus activos, puede estar seguro de que volveré con preguntas sobre los servicios de Windows próximamente :)) seguirá revisando la carpeta de cada agente si hay nuevos activos allí. , y si los hay, la base de datos se actualizará y para algunas de ellas se crearán páginas html estáticas. Como podría llevarles un tiempo cargar todo y queremos que puedan ver sus cambios cargados de manera directa, pensamos que un hilo por agente sería una buena idea ya que ningún agente necesita esperar a que alguien más lo haga. terminar (y tenemos múltiples procesadores, así que queríamos usar su capacidad total). Espero que esto lo explique!

Gracias,

Annelie

+0

Un poco de tangente, pero es posible que desee tratar de hacer que los hilos sean un poco más impulsados ​​por eventos en lugar de ejecutarse en un circuito cerrado. Correr en un círculo cerrado de esa manera probablemente terminará martillando su procesador y desperdiciando recursos, y haciendo que los hilos que tienen trabajo real que hacer simplemente se queden sentados por períodos de tiempo más largos. – Kitsune

+0

Más hilos no son necesariamente la respuesta y pueden convertirse en un problema. Entonces diga que tiene 20 agentes y genera un hilo para cada uno. El archivo de E/S siempre será un cuello de botella, por lo que tiene 20 subprocesos que sondean constantemente el sistema de archivos en busca de cambios, lo que tendrá un impacto negativo en el rendimiento. Cada uno de esos subprocesos también usará tiempo de CPU para ese sondeo, por lo que en un recuadro de cuatro núcleos cada núcleo recibiría cinco de estos subprocesos (suponiendo 20 agentes), por lo que un subproceso que está haciendo un trabajo real (procesamiento los nuevos archivos) se intercambiarán para permitir la ejecución del sondeo. – Ragoczy

Respuesta

12

Teniendo en cuenta el uso específico de su describen (ver los archivos), me gustaría sugerir que utilice un FileSystemWatcher para determinar cuando hay nuevos archivos y luego desencadenar un hilo con el grupo de hilos para procesar los archivos hasta que no haya más que procesar, en cuyo punto el hilo sale.

Esto debería reducir la E/S (ya que no está sondeando constantemente el disco), reducir el uso de la CPU (ya que el bucle constante de múltiples hilos sondeando el disco usaría ciclos) y reducir el número de subprocesos que ejecuta en cualquier momento (suponiendo que no se realizan modificaciones constantes en el sistema de archivos).

Es posible que desee abrir y leer los archivos solo en el hilo principal y pasar los datos a los hilos de trabajo (si es posible), para limitar la E/S a un único hilo.

+0

Estaba a punto de publicarlo yo mismo. –

+1

Definitivamente un enfoque más sensato. –

+0

Este es el enfoque correcto. El controlador de eventos FileSystemWatcher debe publicar nuevos archivos en una cola, que es supervisada por una secuencia de supervisor separada que genera hilos de trabajo separados para ingerir los archivos. Esto le permite controlar la cantidad de subprocesos de trabajo y minimizar las posibilidades de desbordamiento de búfer de FileSystemWatcher. Cada subproceso de trabajo debe probar continuamente hasta que obtenga acceso exclusivo a su archivo para que no empiece a leer hasta que haya finalizado la escritura del archivo. –

2

Un problema con ThreadPool sería que si la piscina pasa a ser menor que el número de agentes que le gustaría tener, los que tratan de empezar más tarde no puede ejecutar . Es posible que algunas tareas nunca comiencen a ejecutarse, y también podría matar de hambre todo lo demás en el dominio de la aplicación que también utiliza el grupo de subprocesos. Probablemente es mejor que no vayas por esa ruta.

+0

@tehMick ¡Punto interesante! ¿Tiene alguna sugerencia sobre qué hacer en su lugar? La razón por la que queríamos hacer threading era que no queremos que nadie que esté cargando cosas tenga que esperar demasiado tiempo, y como tenemos múltiples procesadores, usamos toda su capacidad. – annelie

+0

Si está monitoreando un sistema de archivos, definitivamente haría eso en un único hilo, ya que varios hilos simplemente pelearían por el acceso al archivo. Luego, cada archivo que encuentre se puede poner en cola como un elemento de trabajo para que el grupo de subprocesos recupere. Pero hay varias otras formas válidas de abordarlo. –

+0

Aunque, pensando más en ello, podría estar malinterpretando el caso de uso aquí, no estoy completamente claro sobre el contexto. –

-1

Hasta que actualice a .NET 4, el ThreadPool podría ser su mejor opción. También puede usar un semáforo y un evento AutoReset para controlar el número de subprocesos concurrentes. Si está hablando de un trabajo prolongado, la sobrecarga de iniciar y administrar sus propios hilos es baja y la solución es más elegante. Eso le permitirá usar WorkerThread.Join() para asegurarse de que todos los hilos de trabajo estén completos antes de reanudar la ejecución.

+0

Supongo que while (true) es solo psuedocode. –

1

Un grupo de subprocesos es útil cuando espera que los subprocesos entren o desaparezcan con bastante regularidad, no para un número predefinido de subprocesos.

+0

@Tejs Sí, entiendo tu punto. ¿Alguna sugerencia de qué hacer en su lugar?(mira mi comentario anterior para saber por qué fuimos para esto) – annelie

+0

Nunca implementaría un ciclo while (verdadero) - eso es imposible de determinar a menos que quieras lanzar una excepción, o simplemente matar el hilo. Si necesita tener simultaneidad, considere hacer algo como esto:

 Thread x = new Thread(new ThreadStart(Foo)); x.Start(); // If Some conditions change later, and you want to kill it, call x.Abort() public void Foo() { // Do Stuff } 
Tejs

2

Definitivamente no desea utilizar el ThreadPool para este propósito. Los subprocesos de ThreadPool no están destinados a ser utilizados para tareas de ejecución prolongada (los recuentos "infinitos" son de ejecución prolongada), ya que eso obviamente uniría los recursos destinados a ser compartidos.

Para su aplicación, probablemente sería mejor crear un hilo (no del ThreadPool) y en ese hilo de ejecutar el bucle while, dentro de los cuales iterar a través de su colección Agentes y realizar el procesamiento para cada uno . En el bucle while también debe utilizar una llamada Thread.Sleep para no agotar el procesador (existen mejores formas de ejecutar el código periódicamente, pero Thread.Sleep funcionará para sus fines).

Finalmente, debe incluir alguna forma para que el bucle while salga cuando finalice su programa.

Actualización: Por último, finalmente, multi-threading hace no automáticamente acelerar código de ejecución lenta. Nueve mujeres no pueden tener un bebé en un mes.

+1

Pero una mamá mamá puede hacer un bebé por mes ... :-P –

+1

Aunque el roscado generalmente HACE acelerar el tiempo de procesamiento, especialmente en estos muchos- procesadores centrales de máquinas modernas de escritorio y servidor. Hasta que no haya un solo recurso que cada hilo necesite, se ejecutarán más rápido incluso en una sola máquina central. ¡Además, ThreadPool está destinado a ser utilizado! Realmente no creo que signifiquen mientras (verdadero) que no sea para los propósitos de psudocode. –

+0

@Nate: el OQ dijo "Quiero que sigan funcionando y nunca terminen", lo que interpreté como que querían decir 'while (true)' literalmente. Por supuesto, ThreadPool está destinado a ser utilizado, pero no de esta manera. – MusiGenesis

0

Hmm .. como señala Ragoczy, es mejor usar FileSystemWatcher para supervisar los archivos. Sin embargo, dado que tiene operaciones adicionales, puede pensar en términos de subprocesamiento múltiple.

Pero tenga cuidado, no importa cuántos procesadores tenga, hay un límite en su capacidad. Puede que no desee crear tantos hilos como el número de usuarios simultáneos, por la sencilla razón de que su número de agentes puede aumentar.

Cuestiones relacionadas