2010-04-22 12 views
10

Nuestro escenario es un escáner de red.En .NET, ¿hay un programador de subprocesos para subprocesos de larga ejecución?

Se conecta a un conjunto de hosts y los escanea en paralelo durante un tiempo utilizando subprocesos de fondo de baja prioridad.

Quiero poder programar un montón de trabajo pero solo tengo un número de diez o cualquier cantidad de hosts analizados en paralelo. Incluso si creo mis propios hilos, las muchas devoluciones de llamada y otras bondades asincrónicas utilizan el ThreadPool y termino quedándome sin recursos. Debería mirar MonoTorrent ...

Si uso THE ThreadPool, ¿puedo limitar mi aplicación a algún número que dejará suficiente para que el resto de la aplicación funcione sin problemas?

¿Hay un subproceso de subprocesos que puedo inicializar a n subprocesos de larga duración?

[Editar] Nadie parece haber notado que hice algunos comentarios sobre algunas respuestas, así que añadiré un par de cosas aquí.

  • Las discusiones deben ser cancelables tanto con gracia y fuerza.
  • Los subprocesos deben tener baja prioridad dejando la GUI en buen estado.
  • Los subprocesos son de larga ejecución pero en orden (minutos) y no en orden (días).

trabajo para un host de destino dado es básicamente:

For each test 
    Probe target (work is done mostly on the target end of an SSH connection) 
    Compare probe result to expected result (work is done on engine machine) 
    Prepare results for host 

¿Puede alguien explicar por qué utilizar la utilidad negativa SmartThreadPool está marcado ingenio ha?

+0

respuesta de Jeff esternal parece adecuado, aunque en lugar de BackgroundWorker que podría ser mejor crear sus propias instancias 'System.Threading.Thread'. Sin embargo, también menciona que incluso dentro de sus propios subprocesos, se está quedando sin recursos de grupo de subprocesos debido a las operaciones asincrónicas. Tal vez deberías explicar por qué estás realizando operaciones asincrónicas dentro de un hilo que has dedicado específicamente a ejecutar esas operaciones. –

+0

Después de buscar un poco más me encontré con otro ThreadPool http://smartthreadpool.codeplex.com/ que podría llegar al punto. Uso cosas asincrónicas en el subproceso de trabajo para manejar Salida y Errores a medida que ocurren. A medida que se ejecuta la aplicación, los usuarios reciben comentarios para que vean qué tan avanzado está cada tarea. – LogicMagic

+0

La aplicación está escrita usando GTK # y el patrón MVC. Hay una GUI donde cuando se activan ciertos eventos, el hilo de la interfaz gráfica de usuario se organiza y se realizan actualizaciones.El escaneo no es simple, la aplicación es un escáner autenticado que observa la configuración de los objetivos. Una exploración debe tomar O (minutos) de tiempo para completarse. por host Algunos informes por host se realizan en la máquina del motor en el hilo por host por razones obvias. Se crea un proceso por conexión que probablemente sea costoso, pero en comparación con los minutos, no importa. – LogicMagic

Respuesta

8

En .NET 4 tiene el Task Parallel Library integrado. Cuando crea una nueva Tarea (la nueva abstracción de hilo) puede especificar que una Tarea sea de larga ejecución. Hemos hecho buenas experiencias con eso (días largos en lugar de minutos u horas).

Puede usarlo también en .NET 2, pero en realidad es una extensión, marque here.

En VS2010 los depuración de aplicaciones paralelas basados ​​en tareas (hilos) no ha sido mejorado radicalmente . Se recomienda usar Tareas siempre que sea posible en lugar de hilos crudos. Ya que le permite manejar el paralelismo de una manera más orientada a objetos.

ACTUALIZACIÓN
tareas que no están especificados como carreras de larga , se ponen en cola en el grupo de subprocesos (o cualquier otro programador para el caso).
Pero si se especifica una tarea para ser carreras de larga, sólo se crea un hilo independiente , ningún grupo de subprocesos está involucrado.

+0

¿TPL no se sienta encima del ThreadPool? – LogicMagic

+0

El propósito del TPL es agregar una capa de abstracción capaz de sentido al enhebrar y programar diferentes tareas. La belleza del TPL es que puedes especificar ** un programador **. El programador ** CAN ** de hecho es el grupo de subprocesos. Pero también puedes definir el tuyo. Para obtener más información, consulte: http://bit.ly/aW4Lq4 y http://bit.ly/9VAkbf – ntziolis

5

CLR ThreadPool no es apropiado para la ejecución de tareas de larga ejecución: es para realizar tareas breves donde el costo de crear un hilo sería casi tan alto como la ejecución del método en sí. (O al menos un porcentaje significativo del tiempo que se tarda en ejecutar el método.) Como ya has visto, .NET en sí mismo consume subprocesos de grupo de subprocesos, no puedes reservarlos por ti mismo para que no te arriesgues a perder el tiempo de ejecución.

El trabajo de programación, aceleración y cancelación es un asunto diferente. No hay otro grupo de subprocesos de cola de trabajo .NET integrado, por lo que tendrá que rodar por sí mismo (administrando el threads o BackgroundWorkers) o buscar uno preexistente (Ami Bar's SmartThreadPool parece prometedor, aunque yo no lo he usado).

+0

Los trabajadores de segundo plano están pensados ​​para programar tareas de larga ejecución mientras se mantiene la UI receptiva. Sin embargo, no son la opción correcta para el enhebrado de lógica de aplicación. – ntziolis

+0

@ntziolis - Estoy de acuerdo, aunque no tenemos suficiente información sobre la aplicación para descartarla por completo: un 'escáner de red' podría significar [una aplicación GUI] (http://www.softperfect.com/products/networkscanner /). –

+0

Eso es cierto, ¿tal vez el creador podría agregar algo de información adicional? – ntziolis

1

En su caso particular, la mejor opción no serían los subprocesos o el grupo de subprocesos o el trabajador de fondo, sino el modelo de programación asincrónico (BeginXXX, EndXXX) proporcionado por el marco.

Las ventajas de usar el asynchronous model es que la pila TcpIp utiliza devoluciones de llamada cuando hay datos para leer y la devolución de llamada se ejecuta automáticamente en un hilo del grupo de subprocesos.

Usando el asynchronous model, puede controlar el número de solicitudes por intervalo de tiempo iniciado y también puede iniciar todas las solicitudes de un hilo de menor prioridad mientras procesa las solicitudes en un subproceso de prioridad normal lo que significa que los paquetes se mantendrán lo menos posible en la Cola Tcp interna de la pila de red.

Asynchronous Client Socket Example - MSDN

P. S. Para múltiples trabajos simultáneos y de larga ejecución que no hacen gran cantidad de cálculos, pero sobre todo esperan en IO (red, disco, etc.) la mejor opción siempre es usar un mecanismo de devolución de llamada y no hilos.

1

Crearía su propio administrador de hilos. En el siguiente ejemplo simple, se utiliza una cola para contener hilos en espera y se utiliza un diccionario para contener hilos activos, codificados por ManagedThreadId. Cuando termina un hilo, se elimina del diccionario activo y lanza otro hilo a través de una devolución de llamada.

Puede cambiar el límite máximo de ejecución de subprocesos de su UI y puede pasar información adicional a la devolución de llamada ThreadDone para supervisar el rendimiento, etc. Si un subproceso falla, por ejemplo, un tiempo de espera de red, puede volver a insertar en la cola . Añadir métodos de control adicionales al supervisor para hacer una pausa, detener, etc.

using System; 
using System.Collections.Generic; 
using System.Threading; 

namespace ConsoleApplication1 
{ 
    public delegate void CallbackDelegate(int idArg); 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      new Supervisor().Run(); 
      Console.WriteLine("Done"); 
      Console.ReadKey(); 
     } 
    } 

    class Supervisor 
    { 
     Queue<System.Threading.Thread> waitingThreads = new Queue<System.Threading.Thread>(); 
     Dictionary<int, System.Threading.Thread> activeThreads = new Dictionary<int, System.Threading.Thread>(); 
     int maxRunningThreads = 10; 
     object locker = new object(); 
     volatile bool done; 

     public void Run() 
     { 
      // queue up some threads 
      for (int i = 0; i < 50; i++) 
      { 
       Thread newThread = new Thread(new Worker(ThreadDone).DoWork); 
       newThread.IsBackground = true; 
       waitingThreads.Enqueue(newThread); 
      } 
      LaunchWaitingThreads(); 
      while (!done) Thread.Sleep(200); 
     } 

     // keep starting waiting threads until we max out 
     void LaunchWaitingThreads() 
     { 
      lock (locker) 
      { 
       while ((activeThreads.Count < maxRunningThreads) && (waitingThreads.Count > 0)) 
       { 
        Thread nextThread = waitingThreads.Dequeue(); 
        activeThreads.Add(nextThread.ManagedThreadId, nextThread); 
        nextThread.Start(); 
        Console.WriteLine("Thread " + nextThread.ManagedThreadId.ToString() + " launched"); 
       } 
       done = (activeThreads.Count == 0) && (waitingThreads.Count == 0); 
      } 
     } 

     // this is called by each thread when it's done 
     void ThreadDone(int threadIdArg) 
     { 
      lock (locker) 
      { 
       // remove thread from active pool 
       activeThreads.Remove(threadIdArg); 
      } 
      Console.WriteLine("Thread " + threadIdArg.ToString() + " finished"); 
      LaunchWaitingThreads(); // this could instead be put in the wait loop at the end of Run() 
     } 
    } 

    class Worker 
    { 
     CallbackDelegate callback; 
     public Worker(CallbackDelegate callbackArg) 
     { 
      callback = callbackArg; 
     } 

     public void DoWork() 
     { 
      System.Threading.Thread.Sleep(new Random().Next(100, 1000)); 
      callback(System.Threading.Thread.CurrentThread.ManagedThreadId); 
     } 
    } 
} 
Cuestiones relacionadas