我正在尝试了解wcf中的并发性并从here下载了示例代码并对测试双向调用进行了一些更改。令我惊讶的是,我无法看到并发对双向调用的影响(虽然我可以看到单向调用的并发性)。 这是WCF并发模型的工作方式吗? (要么) 我做错了什么?
这是服务代码。
[ServiceContract]
public interface IHelloWorldService
{
[OperationContract(IsOneWay=true)]
void Call(string ClientName);
[OperationContract]
string GetData(int value);
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
}
[DataContract]
public class CompositeType
{
bool boolValue = true;
string stringValue = "Hello ";
[DataMember]
public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}
[DataMember]
public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class HelloWorldService : IHelloWorldService
{
public static int counter;
public HelloWorldService()
{
counter++;
}
public void Call(string ClientName)
{
Console.WriteLine("Instance:" + counter.ToString() + " Thread:" + Thread.CurrentThread.ManagedThreadId.ToString() + " Time:" + DateTime.Now.ToString() + "\n\n");
Thread.Sleep(5000);
}
public string GetData(int value)
{
Console.WriteLine("Instance:" + counter.ToString() + " Thread:" + Thread.CurrentThread.ManagedThreadId.ToString() + " Time:" + DateTime.Now.ToString() + "\n\n");
Thread.Sleep(5000);
return value.ToString();
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
Console.WriteLine("Instance:" + counter.ToString() + " Thread:" + Thread.CurrentThread.ManagedThreadId.ToString() + " Time:" + DateTime.Now.ToString() + "\n\n");
Thread.Sleep(5000);
return composite;
}
}
这是服务托管代码。
class Program
{
static void Main(string[] args)
{
//Create a URI to serve as the base address
//Uri httpUrl = new Uri("net.tcp://localhost:8001/HelloWorld");
Uri httpUrl = new Uri("http://localhost:8010/MyService/HelloWorld");
//Create ServiceHost
ServiceHost host
= new ServiceHost(typeof(ClassLibrary1.HelloWorldService), httpUrl);
//Add a service endpoint
host.AddServiceEndpoint(typeof(ClassLibrary1.IHelloWorldService)
, new WSHttpBinding(), "");
//Enable metadata exchange
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
host.Description.Behaviors.Add(smb);
ServiceThrottlingBehavior stb = new ServiceThrottlingBehavior();
stb.MaxConcurrentCalls = 100;
stb.MaxConcurrentInstances = 100;
stb.MaxConcurrentSessions = 100;
host.Description.Behaviors.Add(stb);
//Start the Service
host.Open();
Console.WriteLine("Service is host at " + DateTime.Now.ToString());
Console.WriteLine("Host is running... Press <Enter> key to stop");
Console.ReadLine();
}
}
这是客户端代码。
class Program
{
static int m_NumberOfWorkers = 10;
static readonly object m_Locker = new object();
static bool flag_GO = false;
static Stopwatch m_OverAllStopwatch = new Stopwatch();
static ConcurrentBag<Stopwatch> m_bagIndividualStopwatch = new ConcurrentBag<Stopwatch>();
static int m_CompletedWorkers = 0;
static ServiceReference1.HelloWorldServiceClient m_objProxy;
static int m_KindOfMethod;
static void Main(string[] args)
{
while(true)
{
try
{
flag_GO = false;
Console.WriteLine("Enter number of concurrent clients:");
m_NumberOfWorkers = Int32.Parse(Console.ReadLine());
Console.WriteLine("Kind of method (1: One way, 2: Two way 3: Two way using data contract):");
m_KindOfMethod = Int32.Parse(Console.ReadLine());
// Create Workers
List<Thread> lstThreads = new List<Thread>();
for (int i = 0; i < m_NumberOfWorkers; ++i)
{
lstThreads.Add(new Thread(WaitOnPulse));
}
// Start Workers
for (int i = 0; i < lstThreads.Count; ++i)
{
lstThreads[i].Start();
}
m_objProxy = new ServiceReference1.HelloWorldServiceClient();
m_OverAllStopwatch.Restart();
// Signal all workers
lock (m_Locker)
{
flag_GO = true;
Monitor.PulseAll(m_Locker);
}
// Wait all workers to finish
for (int i = 0; i < lstThreads.Count; ++i)
{
lstThreads[i].Join();
}
m_objProxy.Close();
m_objProxy = null;
}
catch
{
return;
}
}
}
private static void WaitOnPulse()
{
lock (m_Locker)
{
while (!flag_GO) Monitor.Wait(m_Locker);
}
TestWhatEverYouWant();
IamDone();
}
private static void TestWhatEverYouWant()
{
Stopwatch stopWatch = Stopwatch.StartNew();
//Thread.Sleep(1000);
switch (m_KindOfMethod)
{
case 1:
m_objProxy.Call(m_NumberOfWorkers.ToString() + "Client Calls");
break;
case 2:
m_objProxy.GetData(m_NumberOfWorkers);
break;
case 3:
ServiceReference1.CompositeType objData = new ServiceReference1.CompositeType();
m_objProxy.GetDataUsingDataContract(objData);
break;
}
stopWatch.Stop();
m_bagIndividualStopwatch.Add(stopWatch);
}
private static void IamDone()
{
Interlocked.Increment(ref m_CompletedWorkers);
// Summarize results if all workers are done
if (Interlocked.CompareExchange(ref m_CompletedWorkers, 0, m_NumberOfWorkers) == m_NumberOfWorkers)
{
m_OverAllStopwatch.Stop();
Console.WriteLine("OverAll Elapsed Time: {0}", m_OverAllStopwatch.ElapsedMilliseconds);
Stopwatch stopWatch;
while (m_bagIndividualStopwatch.TryTake(out stopWatch))
//foreach (Stopwatch stopWatch in m_bagIndividualStopwatch)
{
Console.WriteLine("Individual Elapsed Time: {0}", stopWatch.ElapsedMilliseconds);
}
}
}
}
这是Cleint追踪:
Enter number of concurrent clients:
8
Kind of method (1: One way, 2: Two way 3: Two way using data contract):
2
OverAll Elapsed Time: 42022
Individual Elapsed Time: 42021
Individual Elapsed Time: 37013
Individual Elapsed Time: 32008
Individual Elapsed Time: 26987
Individual Elapsed Time: 21981
Individual Elapsed Time: 16980
Individual Elapsed Time: 11968
Individual Elapsed Time: 6985
这是服务器跟踪:
Instance:1 Thread:6 Time:12/17/2012 8:09:29 PM
Instance:1 Thread:5 Time:12/17/2012 8:09:34 PM
Instance:1 Thread:7 Time:12/17/2012 8:09:39 PM
Instance:1 Thread:7 Time:12/17/2012 8:09:44 PM
Instance:1 Thread:5 Time:12/17/2012 8:09:49 PM
Instance:1 Thread:7 Time:12/17/2012 8:09:54 PM
Instance:1 Thread:5 Time:12/17/2012 8:09:59 PM
Instance:1 Thread:7 Time:12/17/2012 8:10:04 PM
对于这些结果,您可以清楚地看到请求是按顺序处理的。理想情况下,我期待所有8个并发请求将在5秒内完成。但是花了大约42秒完成。
答案 0 :(得分:0)
我的代码中的问题是代理的使用方式。我为所有并发客户端创建了一个代理,并且所有对服务的调用都只通过此代理进行。因此,所有这些呼叫都在通道中排队。 为每个客户创建一个代理 ,模拟wcf负载测试的方式,解决了问题。
答案 1 :(得分:-1)
我仍然认为问题在于设置;代理和源自每个代理的线程数,链接解释得很好。
另请看下面的链接;可能是测试客户端可能有问题。 Seeking WCF Duplex "TwoWay" Subscribe+Callback Example