HXD
HXD

Reputation: 506

How to send messages for a short time span

I am trying to send about 20 messages for a given time span. I want to log the time the request is received. Now For this time shown below

        var startTime = DateTime.Now;
        var timeoutSpan = TimeSpan.FromMilliseconds(1000);
        var count = 0;
        while ((DateTime.Now - startTime) <= timeoutSpan)
        {
            foreach (string message in messages)
            {
                txtRequest.Text = message;
                //this sends request to my service that logs a request
                sendMessageResult = client.SendMessage("Test", txtRequest.Text);
                 count++;
            }

        }

Lets say I send the message around Time = 2014-03-06 09:46:47:334 AM

I want the recieved time of the request of all the messages in a loop to be very similar but right now the gap is as followes

request A Time = 2014-03-06 09:46:47:334 AM
count:1
request B Time = 2014-03-06 09:46:47:385 AM
count:2
request C Time = 2014-03-06 09:46:47:414 AM

App.config

  <system.serviceModel>
  <behaviors>
     <serviceBehaviors>
    <behavior name="meta">
      <serviceMetadata httpGetEnabled="true" />
      </behavior>
  </serviceBehaviors>
  </behaviors>
   <services>
  <service behaviorConfiguration="meta" name="MyService.Operator">
    <endpoint address="" binding="basicHttpBinding" contract="MyService.IOperator" />

    <host>
      <baseAddresses>
       <add baseAddress="http://MyService" />  
      </baseAddresses>
    </host>
  </service>
</services>

How can I make the milliseconds of the requests to be very close or Equal(if possible) to one another? as you can see request B is has .385 milliseconds how can I make a request which are sent around same time?

Upvotes: 0

Views: 197

Answers (2)

rene
rene

Reputation: 42453

If you leverage the TPL in my limited testing (client and server on the same box and client and server on seperate boxes with a GB network connection) I gain better results if I don't reuse the wcf-client but create a new one for every thread. I tested this with the default VS2010 WcfApplication template as a x64 .Net 4.0 executable.

My code looks like this:

// no multi-threading, one client
var sw = new System.Diagnostics.Stopwatch();
sw.Start();
using (var wc = new ServiceReference1.Service1Client())
{
    for (int x = 0; x < 200; x++)
    {
        wc.SendMessage("test", messages[x]);
    }
}
sw.Stop();
Console.WriteLine("plain for: {0} ms", sw.ElapsedMilliseconds);
sw.Reset();

// classic Threadpool 
sw.Start();
using (var wc = new ServiceReference1.Service1Client())
{
    var _countdown = new CountdownEvent(200);
    for (int x = 0; x < 200; x++)
    {
        ThreadPool.QueueUserWorkItem((state) =>
            {
                // try/catch to guarantee that _countdown.Signal is always called
                try
                {
                    wc.SendMessage("Test",messages[(int) state]);
                }
                finally
                {
                    _countdown.Signal();
                }
            }, x);
    }
    _countdown.Wait();
}
sw.Stop();
Console.WriteLine("ThreadPool: {0} ms", sw.ElapsedMilliseconds);
sw.Reset();

// multi-threading, one wcf client
sw.Start();
using (var wc = new ServiceReference1.Service1Client())
{
    Parallel.For(0, 200, x =>
        {
            wc.SendMessage("test", messages[x]);
        });
}
sw.Stop();
Console.WriteLine("tpl  paralel for: {0} ms", sw.ElapsedMilliseconds);
sw.Reset();

// multi-threading, client per thread
sw.Start();
int cnt = 0;
Parallel.For(
    0, 
    200, 
    () => { return new ServiceReference1.Service1Client(); },
    (x,pls,wc) =>
    {
        wc.SendMessage("test", messages[x]);
        System.Threading.Interlocked.Increment(ref cnt); // for all done check
        return wc;
    }, 
    client => {client.Close(); ((IDisposable) client).Dispose();}
);                
sw.Stop();
Console.WriteLine("tpl wc per thread paralel for: {0} ms ({1})", sw.ElapsedMilliseconds, cnt);

Typical timings in my network environment (release buid):

plain for: 769 ms
threadpool: 609 ms
tpl  paralel for: 499 ms
tpl wc per thread paralel for: 225 ms

When running everything on the same box the timings between plain and tpl paralel become a lot closer.

Do notice that now and then timings jump due to network and/or cpu loads. I didn't analyze CPU or memeory loads.

Based on this test and setting you could conclude the Parallel.For with per thread creation of the webclient is the quickest.

When optimizing for performance make sure to keep testing, with release builds on your target hardware and only change one parameter/design choice per run.

Upvotes: 0

cvraman
cvraman

Reputation: 1697

You can do:

Parallel.For(0, 20, p =>
{
    var sendMessageResult = client.SendUNIMessage("Test", messages[p]);
});

Upvotes: 1

Related Questions