Что можно сделать для ускорения синхронных вызовов WCF? - PullRequest
4 голосов
/ 09 марта 2010

Мои измерения производительности синхронных вызовов WCF из приложения Silverlight показали, что я могу сделать 7 вызовов / с на локальном соединении, что очень медленно 1004 *. Можно ли это ускорить или это нормально?

Это мой тестовый код:

const UInt32 nrCalls = 100;
ICalculator calculator = new CalculatorClient(); // took over from the MSDN calculator example
for (double i = 0; i < nrCalls; ++i)
{
    var call = calculator.BeginSubtract(i + 1, 1, null, null);
    call.AsyncWaitHandle.WaitOne();
    double result = calculator.EndSubtract(call);
}

Примечания :

  • Загрузка процессора составляет почти 0%. По-видимому, модуль WCF чего-то ждет.
  • Я проверял это как в Firefox 3.6, так и в Internet Explorer 7.
  • Я использую Silverlight v3.0
  • Для сравнения: однажды я написал библиотеку IPC на C ++, и аналогичный тест дал несколько 4000 вызовов / с . Это было без обертки пакетов HTTP, но я не ожидаю, что это сильно замедлит работу. Просто 7 вызовов в секунду невероятно медленные.

Обновление : я перенес клиентскую сторону с Silverlight на .NET, и это решило проблему с производительностью. В этом тесте синхронные вызовы выполняются со скоростью 140 вызовов / с (вместо 7 вызовов / с) и асинхронные вызовы со скоростью 200 вызовов / с (вместо 16 вызовов / с). Видимо, медлительность присуща платформе Silverlight . Мне придется научиться жить с этим.

Ответы [ 2 ]

4 голосов
/ 09 марта 2010

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

В общем, это плохой пример (или хороший пример, показывающий плохую практику). Услуги всегда должны быть грубыми, чтобы избежать накладных расходов на вызовы. Служба, как правило, должна иметь некоторый «вес» в том, что она делает.

Калькулятор может принимать массив операций, поэтому все 100 вычислений могут быть отправлены одновременно, например.

Помните об этом при разработке собственных интерфейсов.

1 голос
/ 09 марта 2010

Используйте асинхронные вызовы и выполняйте их параллельно.

Интернет очень быстрый. На самом деле, вы отправляете запрос, ожидаете вечность, пока (1) сообщение не поступит на сервер, (2) сервер не ответит, (3) ответ, чтобы вернуться обратно (1) и (3) занять время; возможно, в игре есть такие вещи, как «мили до сервера» и «скорость света». А затем вы отправляете следующий запрос и снова делаете ту же игру ожидания. И опять. В цикле.

Следовательно, асинхронные вызовы и параллельные запросы = победа.

(Подсказка: если вы используете F #, асинхронизация может быть очень простой, как в примере ниже.)

open System
open System.Diagnostics 
open System.ServiceModel 

let binding = new BasicHttpBinding()
let address = "http://YOURSERVERMACHINENAME:11111/Blah"

#if SERVER
[<ServiceContract>]
type IMyContract =
    [<OperationContract>]
    abstract member Subtract : x:int * y:int -> int

type MyService() =
    interface IMyContract with
        member this.Subtract(x,y) = x-y

let host = new ServiceHost(typeof<MyService>, new Uri(address))
host.AddServiceEndpoint(typeof<IMyContract>, binding, address) |> ignore
let smb = new Description.ServiceMetadataBehavior()
smb.HttpGetEnabled <- true
host.Description.Behaviors.Add(smb)
host.Open()
Console.WriteLine("service is open")

#else

[<ServiceContract(Name="IMyContract")>]
type IMyClientContract =
    [<OperationContract>]
    abstract member Subtract : x:int * y:int -> int
    [<OperationContract(AsyncPattern=true)>]
    abstract member BeginSubtract : x:int * y:int * c:AsyncCallback * o:obj -> IAsyncResult
    abstract member EndSubtract : r:IAsyncResult -> int

let client = ChannelFactory<IMyClientContract>.CreateChannel(binding, new EndpointAddress(address))
let MAX = 30

let syncSw = Stopwatch.StartNew()
[1..MAX] |> Seq.iter (fun i -> 
    let r = client.Subtract(i,1)
    Console.WriteLine(r))
Console.WriteLine("sync took {0}ms", syncSw.ElapsedMilliseconds)

let AsyncSubtract(x,y) = Async.FromBeginEnd(x, y, client.BeginSubtract, client.EndSubtract)

let asyncSw = Stopwatch.StartNew()
[1..MAX] |> Seq.map (fun i -> async {
    let! r = AsyncSubtract(i,1)
    Console.WriteLine(r)}) 
    |> Async.Parallel |> Async.RunSynchronously |> ignore
Console.WriteLine("async took {0}ms", asyncSw.ElapsedMilliseconds)
#endif

Console.WriteLine("press a key to quit")
Console.ReadKey()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...