Pregunta

Estoy tratando de hacer algunas cosas asíncronas en un método de servicio web. Digamos que tengo la siguiente llamada a la API: http://www.example.com/api.asmx

y el método se llama GetProducts () .

Con estos métodos de GetProducts, hago algunas cosas (p. ej., obtengo datos de la base de datos), justo antes de devolver el resultado, quiero hacer algunas cosas asíncronas (p. ej., enviarme un correo electrónico).

Así que esto es lo que hice.

[WebMethod(Description = "Bal blah blah.")]
public IList<Product> GetProducts()
{
    // Blah blah blah ..
    // Get data from DB .. hi DB!
    // var myData = .......
    // Moar clbuttic blahs :)  (yes, google for clbuttic if you don't know what that is)

    // Ok .. now send me an email for no particular reason, but to prove that async stuff works.
    var myObject = new MyObject();
    myObject.SendDataAsync();

    // Ok, now return the result.
    return myData;
    }
}

public class TrackingCode
{
    public void SendDataAsync()
    {
        var backgroundWorker = new BackgroundWorker();
        backgroundWorker.DoWork += BackgroundWorker_DoWork;
        backgroundWorker.RunWorkerAsync();
        //System.Threading.Thread.Sleep(1000 * 20);
    }

    private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        SendEmail();
    }
}

Ahora, cuando ejecuto este código, el correo electrónico nunca se envía. Si elimino el comentario de Thread.Sleep .., se enviará el correo electrónico.

Entonces ... ¿por qué es que el hilo del trabajador de fondo se destruye? ¿Depende del hilo principal? ¿Es esta la forma incorrecta en la que debería estar haciendo subprocesos de fondo o bifurcados en las aplicaciones web de asp.net?

¿Fue útil?

Solución

BackgroundWorker es útil cuando necesita volver a sincronizar con (por ejemplo) un hilo UI *, por ejemplo, por razones de afinidad. En este caso, parece que el simple uso de ThreadPool sería más que adecuado (y mucho más sencillo). Si tiene volúmenes altos, entonces una cola de productor / consumidor puede permitir una mejor regulación (para que no se ahogue en los hilos), pero sospecho que ThreadPool estará bien aquí ...

public void SendDataAsync()
{
    ThreadPool.QueueUserWorkItem(delegate
    {
        SendEmail();
    });
}

Además, ¿no estoy muy seguro de lo que quieres lograr al dormir? Esto solo atará un hilo (no usa la CPU, pero tampoco sirve). ¿Cuidado para elaborar? Se ve como si estuviera pausando su página web real (es decir, el estado de suspensión ocurre en el hilo de la página web, no en el hilo del correo electrónico). ¿Qué estás tratando de hacer aquí?

* = en realidad, utilizará cualquier contexto de sincronización que esté en su lugar

Otros consejos

Re productor / consumidor; Básicamente, vale la pena mantener algún tipo de acelerador. En el nivel más simple, se podría usar un Semaphore (junto con el ThreadPool ) regular para limitar las cosas a una cantidad conocida de trabajo (para evitar saturar el conjunto de hilos); pero una cola de productor / consumidor probablemente sería más eficiente y administrada.

Jon Skeet tiene esa cola aquí ( CustomThreadPool ). Probablemente podría escribir algunas notas al respecto si quisieras.

Dicho esto: si cancela un sitio web externo, es muy probable que tenga muchas esperas en los puertos de finalización / E / S de la red; como tal, puede tener un número ligeramente mayor de subprocesos ... obviamente (en contraste) si el trabajo estuvo vinculado a la CPU, no tiene sentido tener más subprocesos que los núcleos de la CPU.

Puede descomponerse porque después de 20 segundos, la instancia de BackgroundWorker puede ser recolectada como basura porque no tiene referencias (está fuera del alcance).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top