Groups | Blog | Home
all groups > dotnet web services enhancements > september 2004 >

dotnet web services enhancements : Thread Pooling when using SoapService & SoapClient



DotNetFan NO[at]SPAM Community.nospam
9/28/2004 4:25:02 PM
I am using Classes inherited from SoapService & SoapClient to communicate
between Service and Client Class using soap.tcp for communication. Client
class calls Service every 5 seconds. Both Service & Client Applications keep
on creating & existing new thread every 15 seconds.
Is there any way for enabling thread pooling? Creating a new thread every 15
seconds is a wastage of resources.

Here is simplified code illustrating this problem.

Thanks

**************************************************************
TCPService.cs
**************************************************************
using System;
using Microsoft.Web.Services2.Messaging;

namespace WSE2.TCP
{
[SoapService("someuri.org")]
class TCPService:SoapService
{
[STAThread]
static void Main(string[] args)
{
Console.WriteLine("TCPService");
TCPService tcpService = new TCPService(8080);
Console.ReadLine();
}
public TCPService(int port)
{
string url="soap.tcp://" + System.Net.Dns.GetHostName() + ":" +
port.ToString() + "/TCPService";
SoapReceivers.Add(new Uri(url),this);
Console.WriteLine("Listening at {0}",url);
}
[SoapMethod("SomeMethod")]
public string SomeMethod(string text)
{
Console.WriteLine("{0} {1}",DateTime.Now.ToLongTimeString(),text);
return "Thank you for your input - " + DateTime.Now.ToLongTimeString() +
" : " + text;
}
}
}

**************************************************************
TCPClient.cs
**************************************************************
using System;
using System.Timers;
using Microsoft.Web.Services2;
using Microsoft.Web.Services2.Messaging;

namespace WSE2TCP
{
[SoapService("someuri.org")]
class TCPClient:SoapClient
{
Timer _timer;
[STAThread]
static void Main(string[] args)
{
Console.WriteLine("TCPClient");
TCPClient tcpClient = new TCPClient("soap.tcp://"+
System.Net.Dns.GetHostName()+":8080/TCPService");
Console.ReadLine();
}

public TCPClient(string url):base(new Uri(url))
{
Console.WriteLine("Going to communicate with {0}",url);
_timer = new Timer();
_timer.Elapsed +=new ElapsedEventHandler(_timer_Elapsed);
_timer.AutoReset = true;
_timer.Interval = 5000;
_timer.Enabled = true;
}

public string SomeMethod(string text)
{
SoapEnvelope envelope = base.SendRequestResponse("SomeMethod",text);
return (string)
envelope.GetBodyObject(typeof(string),SoapServiceAttribute.TargetNamespace);
}

private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
//Console.WriteLine("{0} {1}",DateTime.Now.ToLongTimeString(),"Hello");
Console.WriteLine(this.SomeMethod("Hello"));
}
}
}
Hervey Wilson [MSFT]
9/29/2004 8:50:52 PM
[quoted text, click to view]

There's nothing in your code that creates new threads, in general WSE
doesn't create a new thread to handle either clients or receivers,
instead it uses threads from the threadpool to handle events and process
messages. WSE does have some security controls, for example, timeouts
around message processing times, and this may account for some of the
behaviour that you are seeing. You might try disabling these timeouts in
config (see the example wse.config in the product install directory for
details) and see whether this makes a difference.

One other tip would be that you change your use of [STAThread] to
[MTAThread], particularly for an application without user interface. If
you use STAThread it's possible to block the CLR's garbage collection
thread and this will affect the memory usage of your application over time.


--
DotNetFan NO[at]SPAM Community.nospam
9/30/2004 1:39:09 PM
Harvey,

Thanks for reply.

Let me explain the problem in details.

I am using the Serviceside object inherited from SoapService and client side
object inherited from SoapClient.

You correctly identified that I am not creating any new threads. I am just
using WSE to invoke calls to Service every 5 seconds.

You mentioned : "in general WSE doesn't create a new thread to handle either
clients or receivers, instead it uses threads from the threadpool to handle
events and process messages."

We need make sure this statement is really true and that there is no bug in
case of soap.tcp. Unlike soap.http (which use infrastructure and settings of
IIS & ASP.Net enviornment), soap.tcp doesn't have such support from Forms
based projects. I am quite sure that these threads are created by WSE
classes. If I don't make any calls to Service, in timer_elasped handler, then
I don't see any exited threads in a VS window.

This is not my real application, my real code is using Windows form on both
sides. This is a stripped down version to reproduce the problem. I get the
same behavior of creating and exiting from the new thread every 15 seconds,
even in Form based real application.

I also disabled idleTimeout, sendTimeout,receiveTimeout,executionTimeout by
setting them to -1. But it didn't help.

Could you reproduce the problem? Any further hints or directions?

Thanks


[quoted text, click to view]
Hervey Wilson [MSFT]
9/30/2004 9:32:31 PM
[quoted text, click to view]

There are no explicit thread creates anywhere in WSE2, although much use
of made of the CLR threadpool for async results, wait callbacks and some
timers. Given the resolution of 15 seconds, my suspicion is that this is
coming from the message receive timeout engine which is not transport
specific but bound to the SoapReceivers collection. The timeout engine
uses a System.Threading.Timer at that 15 second resolution.

The Framework documentation for this class indicates that it uses the
threadpool, however that does not preclude the case that the threadpool
is creating and destroying a thread to handle the timer callback.
Clearly, if it's the timeout engine then the timer is being set
unnecessarily in the case where timeouts are either disabled or no
messages are being received.

I'll investigate the initiation of the timer problem tomorrow and will
also take a look at switching to a System.Timers.Timer to see if that
alleviates the thread create / destroy. Any changes I make will appear
in the SP2 build of the product.


--
DotNetFan NO[at]SPAM Community.nospam
10/7/2004 8:05:02 AM
Harvey,

Did you identify source of thread creation & destruction? Have you already
fixed the problem?

Thanks



[quoted text, click to view]
Hervey Wilson [MSFT]
10/8/2004 10:39:15 AM
[quoted text, click to view]

I have modified the timeout handling code so that the timer is only
running if there are entries to time out. I am still experimenting to
determine whether using a different timer object alleviates the thread
create/destroy. Per previous, these changes will appear in SP2.


--
Hervey Wilson [MSFT]
10/12/2004 8:10:48 AM
[quoted text, click to view]

System.Threading.Timer is managed directly by the CLR ThreadPool. Any
creation or destruction of threads as a result of this timer therefore
come directly from the CLR itself and cannot be controlled by WSE.


--
DotNetFan NO[at]SPAM Community.nospam
10/12/2004 9:33:06 AM
Harvey,
Do you mean this creation/destruction of new Thread by WSE every 15 seconds
is normal and OK and should n't affect performance.

I need to call a service from client every 5 seconds. I am seeing new thread
created /destroyed by WSE in each Service and Client application every 15
seconds. We are expecting to run Service and client continuously for
days-months. Do you think this is OK.

Thanks.

[quoted text, click to view]
Hervey Wilson [MSFT]
10/14/2004 7:56:12 AM
[quoted text, click to view]

Per earlier comments, WSE is not creating and destroying a thread every
15 seconds, we believe that you are seeing the execution timeout timer
being fired; the thread used to handle the callback is a threadpool
thread. SP2 has been changed so the timer is only active if the
execution timeout is enabled and there are active requests to monitor.

Out of interest, what tool are you using to monitor the threads?



--
DotNetFan NO[at]SPAM Community.nospam
10/14/2004 10:45:03 AM
Harvey,

I am not using any hifi tool to monitor threads.

I am using a Visual Studio to run a solution in debug mode, with two
projects configured to start(multi startup option). I am seeing a new thread
created & destroyed every 15 seconds.

I have posted the code in my first post. It has a simple class inherited
from SoapService on Service side and is using soap.tcp uri to listen.

Client Application is using higher level class inherited from SoapClient.
This class in making call to service every 5 seconds using
System.Timers.Timer.

When I ran these two programs for 2 minutes in Visual Studio debug mode, I
got the following output in Debug.output window.

***********************************************************************
'DefaultDomain': Loaded
'c:\windows\microsoft.net\framework\v1.1.4322\mscorlib.dll', No symbols
loaded.
'DefaultDomain': Loaded
'c:\windows\microsoft.net\framework\v1.1.4322\mscorlib.dll', No symbols
loaded.
'WSE2.TCPClient': Loaded 'C:\Download\Programming\WSE2.0\Tcp
ThreadPool\WSE2.TCP\WSE2.TCPClient\bin\Debug\WSE2.TCPClient.exe', Symbols
loaded.
'WSE2.TCPClient.exe': Loaded
'c:\windows\assembly\gac\microsoft.web.services2\2.0.1.0__31bf3856ad364e35\microsoft.web.services2.dll', No symbols loaded.
'WSE2.TCPClient.exe': Loaded
'c:\windows\assembly\gac\system\1.0.5000.0__b77a5c561934e089\system.dll', No
symbols loaded.
'WSE2.TCPClient.exe': Loaded
'c:\windows\assembly\gac\system.web.services\1.0.5000.0__b03f5f7f11d50a3a\system.web.services.dll', No symbols loaded.
'WSE2.TCPClient.exe': Loaded
'c:\windows\assembly\gac\system.xml\1.0.5000.0__b77a5c561934e089\system.xml.dll', No symbols loaded.
'WSE2.TCPService': Loaded 'C:\Download\Programming\WSE2.0\Tcp
ThreadPool\WSE2.TCP\WSE2.TCPService\bin\Debug\WSE2.TCPService.exe', Symbols
loaded.
'WSE2.TCPClient.exe': Loaded
'c:\windows\assembly\gac\system.security\1.0.5000.0__b03f5f7f11d50a3a\system.security.dll', No symbols loaded.
'WSE2.TCPClient.exe': Loaded
'c:\windows\assembly\gac\system.web\1.0.5000.0__b03f5f7f11d50a3a\system.web.dll', No symbols loaded.
'WSE2.TCPService.exe': Loaded
'c:\windows\assembly\gac\microsoft.web.services2\2.0.1.0__31bf3856ad364e35\microsoft.web.services2.dll', No symbols loaded.
'WSE2.TCPService.exe': Loaded
'c:\windows\assembly\gac\system.web\1.0.5000.0__b03f5f7f11d50a3a\system.web.dll', No symbols loaded.
'WSE2.TCPService.exe': Loaded
'c:\windows\assembly\gac\system\1.0.5000.0__b77a5c561934e089\system.dll', No
symbols loaded.
'WSE2.TCPService.exe': Loaded
'c:\windows\assembly\gac\system.xml\1.0.5000.0__b77a5c561934e089\system.xml.dll', No symbols loaded.
'WSE2.TCPService.exe': Loaded
'c:\windows\assembly\gac\system.security\1.0.5000.0__b03f5f7f11d50a3a\system.security.dll', No symbols loaded.
'WSE2.TCPService.exe': Loaded
'c:\windows\assembly\gac\system.web.services\1.0.5000.0__b03f5f7f11d50a3a\system.web.services.dll', No symbols loaded.
'WSE2.TCPClient.exe': Loaded 'sspv3aum', No symbols loaded.
'WSE2.TCPService.exe': Loaded
'c:\windows\assembly\gac\system.serviceprocess\1.0.5000.0__b03f5f7f11d50a3a\system.serviceprocess.dll', No symbols loaded.
'WSE2.TCPService.exe': Loaded 'o-lkkkuw', No symbols loaded.
'WSE2.TCPClient.exe': Loaded
'c:\windows\assembly\gac\system.serviceprocess\1.0.5000.0__b03f5f7f11d50a3a\system.serviceprocess.dll', No symbols loaded.
The thread '<No Name>' (0x164) has exited with code 0 (0x0).
The thread '<No Name>' (0x9e4) has exited with code 0 (0x0).
The thread '<No Name>' (0xdc4) has exited with code 0 (0x0).
The thread '<No Name>' (0x24c) has exited with code 0 (0x0).
The thread '<No Name>' (0xa1c) has exited with code 0 (0x0).
The thread '<No Name>' (0xad4) has exited with code 0 (0x0).
The thread '<No Name>' (0x4ec) has exited with code 0 (0x0).
The thread '<No Name>' (0x780) has exited with code 0 (0x0).
The thread '<No Name>' (0xa20) has exited with code 0 (0x0).
The thread '<No Name>' (0x560) has exited with code 0 (0x0).
The thread '<No Name>' (0x790) has exited with code 0 (0x0).
The thread '<No Name>' (0x910) has exited with code 0 (0x0).
The thread '<No Name>' (0xd10) has exited with code 0 (0x0).
The program '[3196] WSE2.TCPService.exe' has exited with code 0 (0x0).
The program '[840] WSE2.TCPClient.exe' has exited with code 0 (0x0).
*********************************************************************

Doesn't the following thread exit message indicate Application has handed
over thread for destruction and exit code 0 means application has finished
usage of this thread to execute a code without error? And because this thread
is not from thread pool, application has released it for detruction?

The thread '<No Name>' (0xd10) has exited with code 0 (0x0).

In this run for 2 minutes I got 13 such messages. I am still under
impression WSE is creating & detroying new thread every 15 seconds. I see
constant numbers of total threads in Windows Task Manager under each of these
two applications. It means these threads are being created newly and handed
over for detroy?

Thanks for taking interest in following up my question.




[quoted text, click to view]
DotNetFan NO[at]SPAM Community.nospam
10/15/2004 9:15:10 AM
I did further investigation on another sample application, and used both type
of timers (System.Timers & Thread.Timer) to execute a method every 5 seconds.
In both cases I didn't see thread exit messages when timers called callback
delegate. I confirmed that both timers are really using thread pool by
checking Thread.CurrentThread.IsThreadpool property and it was true.

Threrefore whenever timer fires, we not supposed to see the message
"The thread '<No Name>' (0x164) has exited with code 0 (0x0). "
in debug output.

Then I wrote another method to execute a task repeated every 5 seconds in a
thread from threadpool. Then also I didn't see such message.

Further I manually created a new thread every 5 seconds to execute the same
1 line task, then I started seeing this message in debug when that thread was
exited and handed over to CLR to detroy.

With this experiment I am convinced that the message which I see when I call
a simple method on remote service in WSE repeatedly every 5 seconds, WSE 2.0
is indeed creating new,using and destroying thread every 15 seconds.

Thanks


[quoted text, click to view]
AddThis Social Bookmark Button