.NET Web Service & BackgroundWorker threads

Я пытаюсь сделать некоторые асинхронные вещи в методе webservice. Скажем, у меня есть следующий вызов API: http://www.example.com/api.asmx

и этот метод называется GetProducts().

Я это методы GetProducts, я делаю некоторые вещи (например, получаю данные из базы данных), а затем перед тем, как я верну результат, я хочу сделать некоторые асинхронные вещи (например, отправьте мне электронное письмо).

Так вот что я сделал.

[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();
    }
}

Теперь, когда я запускаю этот код, письмо никогда не отправляется. Если я раскомментирую Thread.Sleep, тогда отправляется электронное письмо.

Итак... почему это так, что рабочий рабочий поток срывается? зависит ли он от родительского потока? Неправильно ли я делать фоновые или разветвленные потоки в веб-приложениях asp.net?

Ответы

Ответ 1

BackgroundWorker полезен, когда вам нужно синхронизировать назад (например) поток пользовательского интерфейса *, например, по причинам близости. В этом случае казалось бы, что просто использование ThreadPool было бы более чем адекватным (и намного проще). Если у вас большие тома, то очередь производителей/потребителей может позволить улучшить дросселирование (чтобы вы не тонули в потоках) - но я подозреваю, что ThreadPool будет в порядке...

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

Кроме того - я не совсем уверен, чего вы хотите достичь, если вы спите? Это будет просто связать поток (не используя CPU, но ничего хорошего не делать). Поразмыслить? Похоже, вы приостановили свою фактическую веб-страницу (т.е. "Сон" происходит в потоке веб-страницы, а не в потоке электронной почты). Что вы здесь делаете?

* = на самом деле, он будет использовать любой синхронный контекст на месте

Ответ 2

Re производитель/потребитель; в основном - просто стоит держать какой-то дроссель. На простейшем уровне можно использовать Semaphore (наряду с регулярным ThreadPool), чтобы ограничить работу известным количеством работы (чтобы избежать насыщения пула потоков); но очередь производителей/потребителей, вероятно, будет более эффективной и управляемой.

У Jon Skeet есть такая очередь здесь (CustomThreadPool). Возможно, я мог бы написать некоторые заметки об этом, если бы вы захотели.

Тем не менее: если вы звоните на внешний веб-сайт, вполне вероятно, что у вас будет много ожиданий в сетевых портах ввода/вывода; как таковое, вы можете иметь немного большее количество потоков... очевидно (наоборот), если работа была связана с ЦП, нет смысла иметь больше потоков, чем у вас есть ядра процессора.

Ответ 3

Он может разорваться, потому что через 20 секунд этот экземпляр BackgroundWorker может быть собран из мусора, поскольку он не имеет ссылок (выходит за рамки).