2010-11-05 2 views
3

У меня есть служба WCF, размещенная в IIS6. Важная часть методы выглядит следующим образом:Будет ли многопоточность увеличивать производительность метода в сервисе WCF?

public MyUser[] GetUsers(string appName, string[] names) 
{ 
    List<User> users = new List<User>(); 
    foreach (string user in names) 
    { 
     MembershipUser mu = this.ADAMProvider.GetUser(user, false); //Unmanaged call to AzMan 
     if (mu != null) 
     { 
     users.Add(MyUser.CreateFrom(mu); 
     } 
    } 
    return users.ToArray(); 
} 

эффективность этого метода очень плохо, когда она вызывается с большим массивом имен пользователей (более 100 или около того). Это может занять более минуты, чтобы вернуться. Кроме того, если этот метод вызывается одновременно более чем одним клиентом, он будет тайм-аут. Я даже видел, как он сбивает пул приложений. Обратите внимание, что в цикле выполняется вызов AzMan. AzMan - неуправляемый COM-компонент.

Чтобы увеличить производительность, я рассматриваю многопоточный подход. .NET 4 не является вариантом, поэтому Parallel.For не вариант, но выполнение эквивалента в 3.5.

Мой вопрос будет создавать кучу нитей (а затем ждать всех перед возвратом) на самом деле увеличить производительность? Есть ли опасность для этого в службе WCF, поддерживаемой IIS6?

ответ

3

Во-первых, я указываю, что компонент COM может быть проблемой в зависимости от состояния квартиры. Однопоточные объекты квартиры могут работать только в одном потоке. Существует автоматическая операция маршаллинга, которая возникает на объектах STA, которая эффективно сериализует все вызовы на нее, поэтому, как бы вы ни старались, может не получить никакого распараллеливания из нее. Даже если это объект MTA, может возникнуть проблема с методом GetUser, если он не предназначен для обеспечения потокобезопасности.

Но если это не проблема, то Я бы использовал ThreadPool вместо создания кучи нитей для этого. Вот как это могло бы выглядеть.

public MyUser[] GetUsers(string appName, string[] names) 
{ 
    int count = 1; // Holds the number of pending work items. 
    var finished = new ManualResetEvent(false); // Used to wait for all work items to complete. 
    var users = new List<User>(); 
    foreach (string user in names) 
    { 
    Interlocked.Increment(ref count); // Indicate that we have another work item. 
    ThreadPool.QueueUserWorkItem(
     (state) => 
     { 
     try 
     { 
      MembershipUser mu = this.ADAMProvider.GetUser(user, false); 
      if (mu != null) 
      { 
      lock (users) 
      { 
       users.Add(MyUser.CreateFrom(mu); 
      } 
      } 
     } 
     finally 
     { 
      // Signal the event if this is the last work item. 
      if (Interlocked.Decrement(ref count) == 0) finished.Set(); 
     } 
     }); 
    } 
    // Signal the event if this is the last work item. 
    if (Interlocked.Decrement(ref count) == 0) finished.Set(); 
    // Wait for all work items to complete. 
    finished.WaitOne(); 
    return users.ToArray(); 
} 

Одна путая вещи о шаблоне я использовал выше, что он относится к основной нити (тот очереди работы), как если бы это был другой элемент работы. Вот почему вы видите код проверки и сигнала в конце цикла. Без него существует очень тонкое условие гонки, которое может возникать между вызовами Set и WaitOne.

Кстати, я должен указать, что TPL доступен в .NET 3.5 в качестве части загрузки Reactive Extensions.

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

+0

+1 для хорошей идеи 'int count = 1;', приводит к многопоточному коду без оператора блокировки, без условий гонки. Я ранее улучшал производительность STA COM, внедряя веб-сервис и помещал его в IIS с помощью Web Garden с 10 активированными процессами. – DxCK

2

Обычно, я бы сказал, что это может помочь - однако, это было бы беспокойство:

Кроме того, если этот метод вызывается одновременно бью более одного клиента, то это будет тайм-аут. Я даже видел, как он сбивает пул приложений. Обратите внимание, что в цикле вызов AzMan производится с помощью bening. AzMan - неуправляемый COM-компонент.

Похоже, что компонент «AzMan» не является потокобезопасным. Если это так, не удастся многократно использовать эту процедуру, поскольку она проводит большую часть своего времени в этой рутине.

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