1

We have Windows Service which reads messages from MSMQ and process it one by one. To improve performance / throughput we moved to TPL. We have couple of database call and WCF call while processing messages. We observed that, while doing WCF call first couple of calls are faster but subsequent call are taking longer time. Here is the sample code.

public class TestWcf
{
    public void Process(string option)
    {
        // container for perellel tasks and WaitAll after 50 count
        TaskContainer batch = new TaskContainer(50, true);

        for (int i = 1; i <= 100; i++)
        {
            if(option.Equals("s"))
            {
                batch.Add(ProcessMessage);
            }
            else
            {
                batch.Add(ProcessMessageAsync);
            }
        }
    }

    public void ProcessMessage()
    {
        Stopwatch sw = Stopwatch.StartNew();

        PostingServiceClient client = new PostingServiceClient();
        client.UpdateArchiveStatus(Guid.Parse("B6D5C77C-330A-4B00-96BF-E91A2B5970E3"),"1234567890");

        sw.Stop();
        Console.WriteLine("Thread {0}, Elapsed Time: {1} s", Thread.CurrentThread.ManagedThreadId, sw.Elapsed.Seconds);
        //client.Close();
    }

    public void ProcessMessageAsync()
    {
        Stopwatch sw = Stopwatch.StartNew();

        PostingServiceClient client = new PostingServiceClient();
        var task = Task.Factory.FromAsync(
            client.BeginUpdateArchiveStatus(Guid.Parse("B6D5C77C-330A-4B00-96BF-E91A2B5970E3"), "1234567890", null,
                null), client.EndUpdateArchiveStatus);
        task.Wait();

        sw.Stop();
        Console.WriteLine("Thread {0}, Elapsed Time: {1} s", Thread.CurrentThread.ManagedThreadId, sw.Elapsed.Seconds);
        //client.Close();
    }

}

We are using external team WCF and it's hosted in IIS Server, App Pool targeting .Net 2.0. WCF Service side, serviceThrottling is 500 and there are NO ServiceBehavior attribute define on Service Contract. We ran above program same time with two console instance one with Sync option and second with Async option. Sync option completed much faster then Async option. My assumption, system is not releasing task from ThreadPool while doing async operation. Question is, which approach is better (Sync vs. Async WCF call) or is there any different approach to deal with WCF call in this scenario.

brijshah
  • 175
  • 1
  • 1
  • 6

1 Answers1

0

Before I get into anything, what framework are you using for the Windows Service? .Net 4.5 (or higher) or .Net 4.0?

The reason why I ask is because if you have async/await (which you need .Net 4.5. for1) then it can dramatically change the simplicity of your code.

Now let's get down to business. So there are some inconsistencies with what you're doing.

What the heck is a TaskContainer? I can't find any documentation on it.

This code block

var task = Task.Factory.FromAsync(
            client.BeginUpdateArchiveStatus(Guid.Parse("B6D5C77C-330A- 4B00-96BF-E91A2B5970E3"),"1234567890", null, null), 
            client.EndUpdateArchiveStatus);

task.Wait();

is NOT asynchronous.

It's synchronous, using a task because of the task.Wait() call. There is going to be a certain amount of overhead to using a Task, but the benefits of the asynchrony and scalability, in most cases, will outweigh this small overhead. That small bit of overhead is going to be better than making a blocking call or blocking a thread to do the network call.

If you wanted a true asynchronous call, you'd need something like this:

var guid = Guid.Parse("B6D5C77C-330A-4B00-96BF-E91A2B5970E3");

// Since I don't have a copy of the operation contract,
// I can't tell if the client call returns a specific type,
// so I'm going to assume it's `void`
var task = Task.Factory.FromAsync(client.BeginUpdateArchiveStatus, client.EndUpdateArchiveStatus, guid, null);

// If you're using .Net 4.5 or higher
// Another side note is that you'll want to return `async Task` instead of `async void` if you decide/can use `await`
await task;
sw.Stop();

// If you're not using .Net 4.0
task.ContinueWith(t =>
  {
   sw.Stop();
   // Whatever code you want to execute now.
  });

To address your assumption:

My assumption, system is not releasing task from ThreadPool while doing async operation.

Task.Factory.FromAsync when used with a truly asynchronous call will not block a ThreadPool thread. (There's tons of resources to verify this, but here's is one that I quickly pulled up.)

Question is, which approach is better (Sync vs. Async WCF call) or is there any different approach to deal with WCF call in this scenario.

Your best bet is to implement the async task correctly.


[1]: If you have VS 2012 or higher, you can pull in the NuGet Package Microsoft.Bcl.Async and get around this for .Net 4.0.

Edit: I just realized I bumped a more than 1 year old question. Oops! That's what I get for skimming the unanswered questions.

Community
  • 1
  • 1
Cameron
  • 2,574
  • 22
  • 37