Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8496849
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 10, 20262026-06-10T23:57:49+00:00 2026-06-10T23:57:49+00:00

I always thought that setting InstanceContextMode to PerCall makes concurrency mode irrelevant even if

  • 0

I always thought that setting InstanceContextMode to PerCall makes concurrency mode irrelevant even if using a session aware binding like net.tcp. This is what MSDN says
http://msdn.microsoft.com/en-us/library/ms731193.aspx
“In PerCallinstancing, concurrency is not relevant, because each message is processed by a new InstanceContext and, therefore, never more than one thread is active in the InstanceContext.”


But today I was going through Juval Lowy’s book Programming WCF Services and he writes in Chapter 8

If the per-call service has a transport-level session, whether
concurrent processing of calls is allowed is a product of the service
concurrency mode. If the service is configured with
ConcurrencyMode.Single, concurrent processing of the pending
calls is not al lowed, and the calls are dispatched one at a time.
[…] I consider this to be a flawed design. If the service is
configured with ConcurrencyMode.Multiple, concurrent pro- cessing is
allowed. Calls are dispatched as they arrive, each to a new instance,
and execute concurrently. An interesting observation here is that in
the interest of through- put, it is a good idea to configure a
per-call service with ConcurrencyMode.Multiple— the instance itself
will still be thread-safe (so you will not incur the synchronization
liability), yet you will allow concurrent calls from the same client.


This is contradicting my understanding and what MSDN says. Which is correct ?
In my case I have a WCF Net.Tcp service used my many client applications that creates a new proxy object, makes the call and then immediately closes the proxy. The service has PerCall InstanceContextMode. Will I get improved throughput if I change the InstanceContextMode to Multiple with no worse thread safety behaviour than percall ?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-10T23:57:50+00:00Added an answer on June 10, 2026 at 11:57 pm

    The key phrase in reading Lowy’s statement is “in the interest of throughput”. Lowy is pointing out that when using ConcurrencyMode.Single WCF will blindly implement a lock to enforce serialization to the service instance. Locks are expensive and this one isn’t necessary because PerCall already guarantees that a second thread will never try to call the same service instance.

    In terms of behavior:
    ConcurrencyMode does not matter for a PerCall service instance.

    In terms of performance:
    A PerCall service that is ConcurrencyMode.Multiple should be slightly faster because its not creating and acquiring the (unneeded) thread lock that ConcurrencyMode.Single is using.

    I wrote a quick benchmark program to see if I could measure the performance impact of Single vs Multiple for a PerCall service: The benchmark showed no meaningful difference.

    I pasted in the code below if you want to try running it yourself.

    Test cases I tried:

    • 600 threads calling a service 500 times
    • 200 threads calling a service 1000 times
    • 8 threads calling a service 10000 times
    • 1 thread calling a service 10000 times

    I ran this on a 4 CPU VM running Service 2008 R2. All but the 1 thread case was CPU constrained.

    Results:
    All the runs were within about 5% of eachother.

    Sometimes ConcurrencyMode.Multiple was faster. Sometimes ConcurrencyMode.Single was faster. Maybe a proper statistical analysis could pick a winner. In my opinion they are close enough to not matter.

    Here’s a typical output:

    Starting Single Service on net.pipe://localhost/base…
    Type=SingleService ThreadCount=600 ThreadCallCount=500
    runtime: 45156759 ticks 12615 msec

    Starting Multiple Service on net.pipe://localhost/base…
    Type=MultipleService ThreadCount=600 ThreadCallCount=500
    runtime: 48731273 ticks 13613 msec

    Starting Single Service on net.pipe://localhost/base…
    Type=SingleService ThreadCount=600 ThreadCallCount=500
    runtime: 48701509 ticks 13605 msec

    Starting Multiple Service on net.pipe://localhost/base…
    Type=MultipleService ThreadCount=600 ThreadCallCount=500
    runtime: 48590336 ticks 13574 msec

    Benchmark Code:

    Usual caveat: This is benchmark code that takes short cuts that aren’t appropriate for production use.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.ServiceModel;
    using System.ServiceModel.Description;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace WCFTest
    {
        [ServiceContract]
        public interface ISimple
        {
            [OperationContract()]
            void Put();
        }
    
        [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]
        public class SingleService : ISimple
        {
            public void Put()
            {
                //Console.WriteLine("put got " + i);
                return;
            }
        }
    
        [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)]
        public class MultipleService : ISimple
        {
            public void Put()
            {
                //Console.WriteLine("put got " + i);
                return;
            }
        }
    
        public class ThreadParms
        {
            public int ManagedThreadId { get; set; }
            public ServiceEndpoint ServiceEndpoint { get; set; }
        }
    
        public class BenchmarkService
        {
            public readonly int ThreadCount;
            public readonly int ThreadCallCount;
            public readonly Type ServiceType; 
    
            int _completed = 0;
            System.Diagnostics.Stopwatch _stopWatch;
            EventWaitHandle _waitHandle;
            bool _done;
    
            public BenchmarkService(Type serviceType, int threadCount, int threadCallCount)
            {
                this.ServiceType = serviceType;
                this.ThreadCount = threadCount;
                this.ThreadCallCount = threadCallCount;
    
                _done = false;
            }
    
            public void Run(string baseAddress)
            {
                if (_done)
                    throw new InvalidOperationException("Can't run twice");
    
                ServiceHost host = new ServiceHost(ServiceType, new Uri(baseAddress));
                host.Open();
    
                Console.WriteLine("Starting " + ServiceType.Name + " on " + baseAddress + "...");
    
                _waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
                _completed = 0;
                _stopWatch = System.Diagnostics.Stopwatch.StartNew();
    
                ServiceEndpoint endpoint = host.Description.Endpoints.Find(typeof(ISimple));
    
                for (int i = 1; i <= ThreadCount; i++)
                {
                    // ServiceEndpoint is NOT thread safe. Make a copy for each thread.
                    ServiceEndpoint temp = new ServiceEndpoint(endpoint.Contract, endpoint.Binding, endpoint.Address);
                    ThreadPool.QueueUserWorkItem(new WaitCallback(CallServiceManyTimes),
                        new ThreadParms() { ManagedThreadId = i, ServiceEndpoint = temp });
                }
    
                _waitHandle.WaitOne();
                host.Shutdown();
    
                _done = true;
    
                //Console.WriteLine("All DONE.");
                Console.WriteLine("    Type=" + ServiceType.Name + "  ThreadCount=" + ThreadCount + "  ThreadCallCount=" + ThreadCallCount);
                Console.WriteLine("    runtime: " + _stopWatch.ElapsedTicks + " ticks   " + _stopWatch.ElapsedMilliseconds + " msec");
            }
    
            public void CallServiceManyTimes(object threadParams)
            {
                ThreadParms p = (ThreadParms)threadParams;
    
                ChannelFactory<ISimple> factory = new ChannelFactory<ISimple>(p.ServiceEndpoint);
                ISimple proxy = factory.CreateChannel();
    
                for (int i = 1; i < ThreadCallCount; i++)
                {
                    proxy.Put();
                }
    
                ((ICommunicationObject)proxy).Shutdown();
                factory.Shutdown();
    
                int currentCompleted = Interlocked.Increment(ref _completed);
    
                if (currentCompleted == ThreadCount)
                {
                    _stopWatch.Stop();
                    _waitHandle.Set();
                }
            }
        }
    
    
        class Program
        {
            static void Main(string[] args)
            {
                BenchmarkService benchmark;
                int threadCount = 600;
                int threadCalls = 500;
                string baseAddress = "net.pipe://localhost/base";
    
                for (int i = 0; i <= 4; i++)
                {
                    benchmark = new BenchmarkService(typeof(SingleService), threadCount, threadCalls);
                    benchmark.Run(baseAddress);
    
                    benchmark = new BenchmarkService(typeof(MultipleService), threadCount, threadCalls);
                    benchmark.Run(baseAddress);
                }
    
                baseAddress = "http://localhost/base";
    
                for (int i = 0; i <= 4; i++)
                {
                    benchmark = new BenchmarkService(typeof(SingleService), threadCount, threadCalls);
                    benchmark.Run(baseAddress);
    
                    benchmark = new BenchmarkService(typeof(MultipleService), threadCount, threadCalls);
                    benchmark.Run(baseAddress);
                }
    
                Console.WriteLine("Press ENTER to close.");
                Console.ReadLine();
    
            }
        }
    
        public static class Extensions
        {
            static public void Shutdown(this ICommunicationObject obj)
            {
                try
                {
                    if (obj != null)
                        obj.Close();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Shutdown exception: {0}", ex.Message);
                    obj.Abort();
                }
            }
        }
    }
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have always thought that in order to connect to SQL server using windows
I always thought that you could use OR in a LIKE statment to query
I always thought that if you didn't implement a heartbeat, there was no way
I always thought that parentheses improved readability, but in my textbook there is a
I always thought that when you dropped a control onto an .aspx page that
I always thought that internal class has access to all data in its external
I always thought that *&p = p = &*p in C. I tried this
I always thought that LIMIT in a query selects only between numbers I set.
I always thought that Core Animation performs animations on the background. When I run
I always thought that a method parameter with a class type is passed as

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.