2011-09-13 14 views
23

Soy uno de esos programadores accidentales, así que no tengo mucho conocimiento sobre la mejor práctica de programación.C# ¿Debería crear un trabajador de fondo o muchos?

Tengo una aplicación que actualmente usa 4 Background Worker.

Así que los declaran:

private BackgroundWorker bw1; 
private BackgroundWorker bw2; 
private BackgroundWorker bw3; 
private BackgroundWorker bw4; 

Entonces configurarlos:

bw1 = new BackgroundWorker(); 
bw1.WorkerReportsProgress = true; 
bw1.DoWork += new DoWorkEventHandler(bw1_DoWork); 
bw1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw1_RunWorkerCompleted); 
bw1.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged); 

bw2 = new BackgroundWorker(); 
bw2.WorkerReportsProgress = true; 
bw2.DoWork += new DoWorkEventHandler(bw2_DoWork); 
bw2.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw2_RunWorkerCompleted); 
bw2.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged); 

bw3 = new BackgroundWorker(); 
bw3.WorkerReportsProgress = true; 
bw3.DoWork += new DoWorkEventHandler(bw3_DoWork); 
bw3.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw3_RunWorkerCompleted); 
bw3.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged); 

bw4 = new BackgroundWorker(); 
bw4.WorkerReportsProgress = true; 
bw4.DoWork += new DoWorkEventHandler(bw4_DoWork); 
bw4.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw4_RunWorkerCompleted); 
bw4.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged); 

Y luego utilice el bw1.RunWorkerAsync(), bw2.RunWorkerAsync(), y así sucesivamente ...

La cosa es que nunca los llamo simultáneamente, se llaman en un punto diferente de una manera bastante lineal.

Así que mi pregunta es, ¿es mejor tener muchos trabajadores de fondo "preconfigurados" o tener uno y cambiar los eventos DoWork y RunWorkerCompleted de acuerdo con lo que quiero que haga?

+5

Si utiliza varios trabajadores de fondo, debe ponerlos en 'List ' para evitar el código redundante. De esta forma, si agrega diez más, no tiene que agregar diez veces la cantidad de código. –

Respuesta

20

Desde un punto de vista arquitectónico, es mejor tener un trabajador de segundo plano separado para cada tarea en segundo plano, que lógicamente no está relacionado con otras tareas de la clase.

0

Hacer su procesamiento utilizando BackgroundWorker significa que lo hace en un hilo separado. Por lo tanto, si no es necesario realizar subprocesos múltiples, no es necesario separar a los trabajadores en segundo plano. Si espera la finalización después de comenzar cada uno de sus trabajadores, puede tener solo un trabajador. También puede eliminar parte de la duplicación de código ...

4

En general, es razonable usar múltiples hilos si ayuda con un uso de recursos más eficiente en su sistema. Para tareas intensivas de CPU, un hilo por núcleo de CPU es un buen punto de partida. Para tareas intensivas de IO, ciertamente puede tener muchas más que eso.

Si tiene la flexibilidad para utilizar .NET 4, buscaría en el Task Parallel Library en lugar de BackgroundWorker. De forma predeterminada, tomará decisiones relativamente inteligentes sobre cuántos subprocesos se ejecutarán simultáneamente además de proporcionar un modelo de programación más fácil.

+0

Voy a echar un vistazo a TPL, estoy usando .NET 4. – Alex

+0

Gracias, también intentaré entender TPL más tarde. –

0

Ejecuta trabajadores con fines de computación. Si el cálculo de una llamada se usa o depende de alguna manera de la otra, puede usar más de un trabajador para lograr un mejor rendimiento (por cierto, este también es un tema para medir). Si solo necesita 4 trabajos y los ejecuta en un hilo separado solo para no bloquear la interfaz de usuario principal, un trabajador es una solución bastante buena.

24

Normalmente utilizo trabajadores de fondo en un patrón bastante diferente. En lugar de definirlos todos a la vez en un principio, incluidos sus respectivos manejadores de eventos, los creo sobre la marcha cuando hago algo que los necesita.

public void SomeEventHandlerMaybe(object sender, EventArgs e) { 
    // do something 

    var bw = new BackgroundWorker(); 
    bw.ReportsProgress = true; 
    bw.DoWork += delegate { 
    // do work. You can use locals from here 
    }; 
    bw.ProgressChanged += delegate { ... }; 
    bw.RunWorkerCompleted += delegate { 
    // do something with the results. 
    }; 
    bw.RunWorkerAsync(); 
} 

Algo así. Tiene la ventaja de que tiene todo el código que hace algo con o en el trabajo de segundo plano en un solo lugar y también en el orden correcto.

+2

No pensé en crearlos sobre la marcha, esa es una buena avenida para mí, ¡gracias! – Alex

+0

+1 ....Este enfoque también puede ahorrar algo de memoria caché :) – Sandy

+0

¿Este enfoque le permite realizar ReportProgress (i) en DoWork y obtener el ProgressPercent dentro del delegado ProgressChanged? – Developr

Cuestiones relacionadas