Служба Windows / WCF и потоки, вопрос для начинающих - PullRequest
3 голосов
/ 18 ноября 2010

У нас есть веб-служба, которая отправляет запросы в службу Windows, в которой размещается служба WCF для обработки.

Интерфейс прост:

namespace MyApp
{
    [ServiceContract]
    public interface IMyApp
    {   
        [OperationContract]
        string DoSomething(string xml);
    }
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    class MyAppWcf : IMyApp
    {
        public string DoSomething(string xml) 
        { 
            Customer customer = GlobalObject.GetCustomer(xml); //millisecs 
            return customer.DoSomething(xml); //Takes 5-10 seconds
        }
    }
}

В WindowsService создается экземпляр GlobalObject.OnStart () и содержит все статические данные, необходимые объектам заказчика.Интерфейс DoSomething () будет вызываться до ок.30 разных клиентов.

Вопросы:1. Каково поведение потоков по умолчанию сейчас?Будет ли каждый звонок ждать, пока последний не закончится?2. Какой эффект окажет изменение InstanceContextMode?

REAL вопрос:Существует до 1000 объектов клиентов, 2 различных объекта клиентов могут быть вызваны параллельно, но один и тот же не может.напримерDoSomething («Клиент 1»);=> Идет впередОтвет за 10 секундDoSomething («Клиент 2»);=> Продвигается параллельно с вышеупомянутым вызовом.DoSomething («Клиент 2»);=> Будет ждать окончания последнего вызова DoSomething («Клиент 2»)

Какими должны быть мои настройки поведения службы, и нужно ли мне реализовать механизм блокировки, чтобы предотвратить одновременную обработку одного и того же объекта более одного раза?

Спасибо.

Редактировать2: GlobalObject.GetCustomer () просто извлекает клиента, упомянутого в XML, из словаря.

Ответы [ 2 ]

2 голосов
/ 18 ноября 2010

OK. Я не уверен, что знал, что ConcurrencyMode игнорируется при использовании инстансинга PerCall, но, глядя на свой собственный проект, я использую инстансинг PerCall и не указываю никакого значения для ConcurrencyMode. Так что, очевидно, я знал это однажды и просто не смог документировать это в своем коде. Теперь это исправлено.

Мой проект работает так же, как вы описали свой, и я использую InstanceContextMode.PerCall, как я уже упоминал. Вот что это значит.

  • Client1 => MyAppWcfInst.DoSomething( "<customer id=A/>" );
  • Client2 => MyAppWcfInst.DoSomething( "<customer id=B/>" );
  • Client3 => MyAppWcfInst.DoSomething( "<customer id=B/>" );

Все три клиента будут взаимодействовать с вашей службой WCF одновременно, но каждый из них будет иметь свой собственный экземпляр и работать в отдельном потоке. Таким образом, хотя каждый вызов каждого клиента является однопоточным, они могут быть активными одновременно. Это означает, что список объектов Customer может быть доступен нескольким клиентам одновременно.

Client1 и Client2 могут работать параллельно, поскольку они имеют дело с различными объектами Customer, но Client3 должен дождаться завершения работы Client2, прежде чем он сможет «что-то сделать» с CustomerB. Все это означает, что вам нужно синхронизировать доступ внутри каждого объекта Customer. Другими словами, логика внутри метода Customer.DoSomething() должна иметь блокировку синхронизации для предотвращения одновременной работы нескольких клиентов с клиентом.

class Customer
{
    private object _sync = new object();

    public string DoSomething( string xml )
    {
        lock (_sync)
        {
            // put your logic here...
        }
    }
}

Так работает моя служба WCF. Надеюсь, это поможет.

1 голос
/ 18 ноября 2010

С PerCall у вас будут запросы к службе, обрабатываемые параллельно, каждый на своем экземпляре класса MyAppWcf. Запросы будут ждать только более раннего завершения, если не существует свободного потока пула потоков .NET для их отправки. Если вы измените его на Single, то запросы будут сериализованы, если вы не установите ConcurrencyMode в Multiple.

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

Аналогично с методом Customer.DoSomething, если он затрагивает какие-либо общие данные (например, сам вызов GlobalObject).

Я не понял, что вы имели в виду, когда «только один объект клиента может обрабатываться одновременно». Если это буквально так, то вам все равно нужно избегать параллельного выполнения.

...