Multithreading 当InstanceContextMode为具有Net.Tcp绑定的WCF服务的PerCall时,多个并发模式是否具有相关性?
我一直认为,将InstanceContextMode设置为PerCall会使并发模式变得无关紧要,即使是使用诸如net.tcp之类的会话感知绑定。这就是MSDN所说的 在PercalInstance中,并发性是不相关的,因为每条消息都由一个新的InstanceContext处理,因此InstanceContext中活动的线程不会超过一个Multithreading 当InstanceContextMode为具有Net.Tcp绑定的WCF服务的PerCall时,多个并发模式是否具有相关性?,multithreading,wcf,Multithreading,Wcf,我一直认为,将InstanceContextMode设置为PerCall会使并发模式变得无关紧要,即使是使用诸如net.tcp之类的会话感知绑定。这就是MSDN所说的 在PercalInstance中,并发性是不相关的,因为每条消息都由一个新的InstanceContext处理,因此InstanceContext中活动的线程不会超过一个 但今天我读了Juval Lowy的书《编程WCF服务》,他在第8章中写道 如果每次呼叫服务具有传输级别会话,则 允许调用的并发处理是服务的一个产品 并发模式。
但今天我读了Juval Lowy的书《编程WCF服务》,他在第8章中写道 如果每次呼叫服务具有传输级别会话,则 允许调用的并发处理是服务的一个产品 并发模式。如果服务配置为 ConcurrencyMode。对挂起的 呼叫不被分配,呼叫一次分配一个。 我认为这是一个有缺陷的设计。如果服务是 配置了ConcurrencyMode。需要多个并发处理 允许。调用在到达时被调度,每个调用都被调度到一个新实例, 并同时执行。一个有趣的观察结果是 出于对吞吐量的兴趣,配置一个 具有ConcurrencyMode.Multiple的每次调用服务-实例本身 仍将是线程安全的(因此您不会导致同步) 但您将允许来自同一客户端的并发调用
这与我的理解和MSDN的说法相矛盾。哪个是正确的?
在我的例子中,我有一个WCF Net.Tcp服务,它使用我的许多客户端应用程序创建一个新的代理对象,进行调用,然后立即关闭代理。该服务具有PerCall InstanceContextMode。如果我将InstanceContextMode更改为Multiple,并且没有比percall更糟糕的线程安全行为,那么吞吐量会提高吗 阅读Lowy陈述的关键短语是“为了吞吐量”。Lowy指出,当使用ConcurrencyMode时,单个WCF将盲目地实现一个锁来强制序列化服务实例。锁是昂贵的,并且这个锁不是必需的,因为PerCall已经保证第二个线程永远不会尝试调用同一个服务实例 在行为方面: ConcurrencyMode对于PerCall服务实例并不重要 在性能方面: 作为ConcurrencyMode.Multiple的PerCall服务应该稍微快一点,因为它不会创建和获取ConcurrencyMode.Single正在使用的(不需要的)线程锁 我编写了一个快速基准测试程序,看看是否可以衡量PerCall服务的单个与多个对性能的影响:基准测试没有显示出有意义的差异。 如果您想自己尝试运行它,我在下面粘贴了代码 我尝试过的测试用例:
- 600个线程调用服务500次
- 200个线程调用服务1000次
- 8个线程调用一个服务10000次
- 1个线程调用服务10000次
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();
}
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用System.ServiceModel;
使用System.ServiceModel.Description;
使用系统文本;
使用系统线程;
使用System.Threading.Tasks;
名称空间WCFTest
{
[服务合同]
公共接口很简单
{
[运营合同()]
无效看跌期权();
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall,ConcurrencyMode=ConcurrencyMode.Single)]
公共类单服务:ISimple
{
公开宣布作废
{
//Console.WriteLine(“put-get”+i);
返回;
}
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall,ConcurrencyMode=ConcurrencyMode.Multiple)]
公共类多重服务:ISimple
{
公开宣布作废
{
//Console.WriteLine(“put-get”+i);
返回;
}
}
公共类线程参数
{
public int-ManagedThreadId{get;set;}
公共ServiceEndpoint ServiceEndpoint{get;set;}
}
公共类基准服务
{
公共只读int ThreadCount;
公共只读int-ThreadCallCount;
公共只读类型ServiceType;
int _completed=0;
System.Diagnostics.Stopwatch\u秒表;
EventWaitHandle\u waitHandle;
完成了;
公共基准测试服务(类型serviceType,int-threadC