2012-07-15 14 views
5
  • Tengo una operación de E/S intensiva.
  • Solo quiero que se ejecuten MAX de 5 subprocesos al mismo tiempo.
  • Tengo 8000 tareas para hacer cola y completar.
  • Cada tarea tarda aproximadamente 15-20 segundos en ejecutarse.

He mirado alrededor en ThreadPool, peroFrustraciones de ThreadPool: creación de subprocesos que supera SetMaxThreads

 ThreadPool.SetMaxThreads(5, 0); 

     List<task> tasks = GetTasks(); 

     int toProcess = tasks.Count; 
     ManualResetEvent resetEvent = new ManualResetEvent(false); 

     for (int i = 0; i < tasks.Count; i++) 
     { 
      ReportGenerator worker = new ReportGenerator(tasks[i].Code, id); 
      ThreadPool.QueueUserWorkItem(x => 
      { 
       worker.Go(); 
       if (Interlocked.Decrement(ref toProcess) == 0) 
        resetEvent.Set(); 
      }); 
     } 

     resetEvent.WaitOne(); 

no puedo entender por qué ... mi código se ejecuta más de 5 hilos a la vez. He intentado establecer maxxreads, establecer conversaciones, pero sigue ejecutando más de 5 hilos.

¿Qué está pasando? ¿Qué me estoy perdiendo? ¿Debo hacer esto de otra manera?

Gracias

+0

Has verificado el valor de ** tasks.Count ** en el depurador? ¿Has intentado simplemente poner "5" en su lugar? –

+0

La matriz de tareas tiene ~ 8000 objetos en ella – Mike

Respuesta

3

tareas de la Biblioteca paralelo puede ayudarle a:

List<task> tasks = GetTasks(); 

Parallel.ForEach(tasks, new ParallelOptions { MaxDegreeOfParallelism = 5 }, 
    task => {ReportGenerator worker = new ReportGenerator(task.Code, id); 
      worker.Go();}); 

What does MaxDegreeOfParallelism do?

+0

¡Esto es tan simple! ¡Y funcionó como un encanto! ¡Gracias! – Mike

1

creo que hay una manera diferente y mejor acercarse a este. (Perdóneme si accidentalmente Java -ize algo de la sintaxis)

El hilo principal aquí tiene una lista de cosas que hacer en "Tareas" - en lugar de crear subprocesos para cada tarea, lo cual no es realmente eficiente cuando tener tantos elementos, crear la cantidad deseada de hilos y luego pedirles que soliciten tareas de la lista según sea necesario.

Lo primero que debe hacer es agregar una variable a la clase de la que proviene este código, para usar como un puntero en la lista. También agregaremos uno para el conteo máximo de hilos deseado.

// New variable in your class definition 
private int taskStackPointer; 
private final static int MAX_THREADS = 5; 

Cree un método que devuelva la siguiente tarea en la lista e incremente el puntero de la pila. A continuación, crear una nueva interfaz para esto:

// Make sure that only one thread has access at a time 
[MethodImpl(MethodImplOptions.Synchronized)] 
public task getNextTask() 
{ 
    if(taskStackPointer < tasks.Count) 
     return tasks[taskStackPointer++]; 
    else 
     return null; 
} 

Alternativamente, usted podría volver tareas [taskStackPointer ++] código, si hay un valor que puede designar en el sentido de "final de la lista".. Sin embargo, probablemente sea más fácil hacerlo de esta manera.

La interfaz:

public interface TaskDispatcher 
{ 
    [MethodImpl(MethodImplOptions.Synchronized)] public task getNextTask(); 
} 

Dentro de la clase ReportGenerator, cambiar el constructor para aceptar el objeto despachador:

public ReportGenerator(TaskDispatcher td, int idCode) 
{ 
    ... 
} 

También debes alterar el ReportGenerator clase para que la el procesamiento tiene un bucle externo que comienza llamando al td.getNextTask() para solicitar una nueva tarea, y que sale del bucle cuando devuelve un NULL.

Por último, modificar el código de la creación del hilo a algo como esto: (esto es sólo para darle una idea)

taskStackPointer = 0; 
for (int i = 0; i < MAX_THREADS; i++) 
{ 
    ReportGenerator worker = new ReportGenerator(this,id); 
    worker.Go(); 
} 

De esta manera se crea el número deseado de hilos y mantenerlos todo funcione a su capacidad máxima .

(No estoy seguro de que tenga el uso de "[MethodImpl (MethodImplOptions.Synchronized)]" exactamente correcto ...Estoy más acostumbrado a Java a C#)

+0

Gracias por tomarse el tiempo para responder a mi pregunta, tiene sentido. Sin embargo, este método es más detallado: P – Mike

+0

Puede ser un poco más detallado, pero una vez que lo tienes en su lugar es bastante eficiente y fácil de entender. –

1

Su lista de tareas tendrá 8k artículos en él porque usted le dijo al código para poner allí :

List<task> tasks = GetTasks(); 

dicho esto, este número no tiene nada que ver con cuántos hilos se están utilizando en el sentido de que el depurador siempre va a mostrar cuántos elementos de su anuncio dedicado a la lista.

Existen varias formas de determinar cuántos subprocesos están en uso. Quizás uno de los más simples es entrar en la aplicación con el depurador y echar un vistazo a la ventana de subprocesos. No solo obtendrá un conteo, sino que verá lo que cada hilo está haciendo (o no) lo que me lleva a ...

Hay una discusión importante acerca de lo que hacen sus tareas y cómo llegó en un número para 'estrangular' el grupo de subprocesos. En la mayoría de los casos de uso, el grupo de subprocesos va a hacer lo correcto.

Ahora para responder a su pregunta específica ...

Para controlar explícitamente el número de tareas simultáneas, consideremos una aplicación trivial que implicaría el cambio de su colección tarea de una lista de BlockingCollection (que usar internamente una ConcurrentQueue) y el siguiente código a 'consumir' la obra:

var parallelOptions = new ParallelOptions 
{ 
    MaxDegreeOfParallelism = 5 
}; 

Parallel.ForEach(collection.GetConsumingEnumerable(), options, x => 
{ 
    // Do work here... 
}); 

Cambio MaxDegreeOfParallelism a cualquier valor concurrente que haya determinado es adecuado para el trabajo que está haciendo.

El siguiente podría ser de interés para usted:

Parallel.ForEach Method

BlockingCollection

Chris

3

Hay una limitación en SetMaxThreads en que nunca se puede establecer más bajo que el número de procesadores en el sistema. Si tiene 8 procesadores, establecerlo en 5 es lo mismo que no llamar a la función en absoluto.

Cuestiones relacionadas