Темы в сервисе WCF - PullRequest
       3

Темы в сервисе WCF

2 голосов
/ 03 декабря 2009

есть кусок кода:

class WCFConsoleHostApp : IBank
{
    private static int _instanceCounter;

    public WCFConsoleHostApp ()
        {
        Interlocked.Increment(ref _instanceCounter);
        Console.WriteLine(string.Format("{0:T} Instance nr " + _instanceCounter + " created", DateTime.Now));
        }
    private static int amount;

    static void Main(string[] args)
    {            
        ServiceHost host = new ServiceHost(typeof(WCFConsoleHostApp));
        host.Open();
        Console.WriteLine("Host is running...");
        Console.ReadLine();
    }

    #region IBank Members

    BankOperationResult IBank.Put(int amount)
    {
        Console.WriteLine(string.Format("{0:00} {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread) + " Putting...");
        WCFConsoleHostApp.amount += amount;
        Thread.Sleep(20000);
        Console.WriteLine(string.Format("{0:00} {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread) + " Putting done");
        return new BankOperationResult { CurrentAmount = WCFConsoleHostApp.amount, Success = true };            
    }

    BankOperationResult IBank.Withdraw(int amount)
    {
        Console.WriteLine(string.Format("{0:00} {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread) + " Withdrawing...");
        WCFConsoleHostApp.amount -= amount;
        Thread.Sleep(20000);
        Console.WriteLine(string.Format("{0:00} {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread) + " Withdrawing done");
        return new BankOperationResult { CurrentAmount = WCFConsoleHostApp.amount, Success = true };
    }

    #endregion
}

Мое тестовое клиентское приложение вызывает этот сервис в 50 потоков (сервис PerCall). Что меня очень беспокоило, так это когда я добавил Thread.Sleep (20000) WCF создает один экземпляр службы в секунду , используя другой поток из пула.

Когда я удаляю Thread.Sleep (20000), сразу создается 50 экземпляров, и для этого используется около 2-4 потоков - что на самом деле я считаю нормальным.

Может кто-нибудь объяснить, почему, когда Thread.Sleep вызывает такие забавные задержки при создании экземпляров?

Ответы [ 4 ]

10 голосов
/ 03 декабря 2009

Вы смешиваете фактическую реализацию службы (реализацию интерфейса IBank) и хост-службу в одном и том же классе.

Это определенно НЕ хорошая практика.

По умолчанию WCF намеренно создает новую отдельную копию класса реализации вашего сервиса для каждого входящего запроса. Это значительно облегчает написание сервиса (не нужно суетиться с многопоточностью - каждый запрос получает свой собственный класс) .

НО : вам не следует смешивать это с ServiceHost, поскольку вам действительно нужен только один экземпляр узла службы для размещения класса службы, который может обрабатывать сотни или тысячи запросов.

Итак - создайте один класс

class BankImplementation : IBank
{
    private static int _instanceCounter;

    BankOperationResult IBank.Put(int amount)
    {
        Console.WriteLine(string.Format("{0:00} {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread) + " Putting...");
        //WCFConsoleHostApp.amount += amount;
        Thread.Sleep(20000);
        Console.WriteLine(string.Format("{0:00} {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread) + " Putting done");
        return new BankOperationResult { CurrentAmount = WCFConsoleHostApp.amount, Success = true };            
    }

    BankOperationResult IBank.Withdraw(int amount)
    {
        Console.WriteLine(string.Format("{0:00} {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread) + " Withdrawing...");
        //WCFConsoleHostApp.amount -= amount;
        Thread.Sleep(20000);
        Console.WriteLine(string.Format("{0:00} {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread) + " Withdrawing done");
        return new BankOperationResult { CurrentAmount = WCFConsoleHostApp.amount, Success = true };
    }
}

для вашего сервисного кода, а затем отдельный (возможно, даже в отдельном проекте все вместе) для размещения вашего сервисного кода:

class WCFConsoleHostApp
{

    public WCFConsoleHostApp ()
    {
        Interlocked.Increment(ref _instanceCounter);
        Console.WriteLine(string.Format("{0:T} Instance nr " + _instanceCounter + " created", DateTime.Now));
    }

    static void Main(string[] args)
    {            
        ServiceHost host = new ServiceHost(typeof(BankImplementation));
        host.Open();
        Console.WriteLine("Host is running...");
        Console.ReadLine();

        host.Close();
    }
}

Теперь вы получаете один экземпляр вашего WCFConsoleHostApp, который увеличит время выполнения WCF на host.Open() и обработает запросы, создавая столько экземпляров класса BankImplementation, сколько необходимо.

ОБНОВЛЕНИЕ: Ну, служба WCF также "удушена", например, Вы можете настроить количество одновременных вызовов и экземпляров. По умолчанию вы получаете 10 одновременных сеансов и 16 одновременных вызовов. Если ваша служба уже обрабатывает 16 одновременных вызовов и они спят в течение некоторого времени, дополнительные экземпляры службы не будут создаваться и обрабатываться.

См. Отличное сообщение в блоге Кенни Вольфа о деталях регулирования обслуживания. Вы можете настроить эти максимумы по своему усмотрению.

2 голосов
/ 03 декабря 2009

Я не знаю, что это правильно, но ...

Возможно, вы сталкиваетесь с поведением ThreadPool, а не с поведением WCF. Поскольку потоки остаются открытыми, поведение ThreadPool может заключаться в том, что он со временем раскручивает дополнительные потоки для обработки работы в очереди, поскольку обычно он пытается уменьшить счетчик потоков для экономии ресурсов.

Таким образом, теоретически WCF затем ставит рабочий элемент в очередь для каждого из запросов, но поскольку потоки не освобождаются в течение двадцати секунд, они не обслуживаются (то есть после первоначального запроса). ThreadPool видит это через секунду, создает новый поток и крадет некоторую работу из существующей очереди. Повторяйте каждую секунду.

0 голосов
/ 03 декабря 2009

Я не уверен на 100% в этом, но вы можете столкнуться с проблемами регулирования с вашей службой WCF. Взгляните на раздел Throttling этой статьи MSDN . Надеюсь, это поможет.

0 голосов
/ 03 декабря 2009

Вы приостанавливаете свой сервис - или имитируете длительные задания. wcf просто создает больше потоков для обработки других клиентов, которые хотят обслуживаться.

...