Silverlight web service callback performance
I have a silverlight client that communicates with a web service on a server. It has a DoSomething method that does nothing and returns void.开发者_开发问答
On the client, I call the service and listen to when the response comes back:
proxy.OnDoSomethingCompleted+=OnDoSomethingCompleted;
t0 = Environment.TickCount;
proxy.DoSomethingAsync();
void DoSomething(..)
{
t1 = Environment.TickCount;
}
Network capture indicates the response is sent back within 2ms. However, OnDoSomethingCompleted is not called until 80ms later. Is there a way to change when the callback is executed?
Normally, OnDoSomethingCompleted() would be executed on the UI thread, i.e., behind the scenes, something is calling some code that (conceptually) looks a little like this:
Dispatcher.BeginInvoke(() => OnDoSomethingCompleted());
This means that OnDoSomethingCompleted() won't get executed until the UI thread decides to cooperate and run it. Most of the time that's fine, but there can be times when you want it to run faster. The basic approach is to use a thread pool to make the original call, which means that the response will get handled from the same thread pool (not necessarily ont he same thread). If you can do some real processing in this return method, and don't just automatically marshal it back onto the UI thread, this can speed up your processing somewhat.
Tomek (from the MS WCF team) gives a good example of how do this here:
http://tomasz.janczuk.org/2009/08/improving-performance-of-concurrent-wcf.html
It's also my understanding that the synchronization context for the WCF connection gets set when you first open it. This means that whatever thread the WCF connection is first opened on is the one that will handle all later calls. So in my own code, I do something like this:
// Spin up the connection on a new worker thread.
// According to Tomek, this will cause all WCF calls to be made from this thread.
ManualResetEvent resetEvent = new ManualResetEvent(false);
wcfWorkerThread = new Thread(new ThreadStart(() => InitializeNotificationClient(resetEvent)));
wcfWorkerThread.Name = "WcfWorkerThread";
wcfWorkerThread.Start();
resetEvent.WaitOne();
And then InitializeNotificationClient() looks something like this:
private void InitializeNotificationClient(ManualResetEvent resetEvent = null)
{
try
{
notificationClient = GetRoomServiceClient();
notificationClient.OpenAsync(callback);
notificationClient.InnerChannel.Faulted += new EventHandler(Channel_Faulted);
notificationClient.InnerChannel.Closed += new EventHandler(Channel_Closed);
}
finally
{
// Tell the waiting thread that we're ready.
if (resetEvent != null)
{
resetEvent.Set();
}
}
}
精彩评论