控制台应用程序和同一客户端中有一个简单的WCF服务。客户端同时(在不同的线程中)向服务器发送N个请求。预计用于处理并发请求的服务器同时分配多个线程,并且在第二个停机时间(特别是由Thread.Sleep(1000)创建)同时将答案返回给客户端,但这不会发生。该服务处理一个线程中的所有请求(这在屏幕截图中的ThreadId中可见),尽管ServiceBehavior属性设置为ConcurrencyMode.Multiple。
服务应用代码:
namespace Server
{
using System;
using System.ServiceModel;
using System.Threading;
[ServiceContract]
public interface IServer
{
[OperationContract]
int GetResult(int value);
}
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple,
InstanceContextMode = InstanceContextMode.Single)]
public class Server: IServer
{
public int GetResult(int value)
{
Console.WriteLine("In: {0}, Time: {1}, ThreadId: {2}",
value, DateTime.Now.TimeOfDay, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(1000);
Console.WriteLine("Out: {0}, Time: {1}, ThreadId: {2}",
value, DateTime.Now.TimeOfDay, Thread.CurrentThread.ManagedThreadId);
return value;
}
}
class Program
{
static void Main()
{
var host = new ServiceHost(new Server());
host.Open();
Console.WriteLine("Service started");
Console.ReadLine();
}
}
}
客户端应用代码:
using System;
namespace Server
{
using System.ServiceModel;
[ServiceContract]
public interface IServer
{
[OperationContract]
int GetResult(int value);
}
}
namespace Client
{
using System.ServiceModel;
using System.Threading;
using Server;
class Program
{
static object lockObj = new object();
static void Main()
{
ChannelFactory<IServer> factory = new ChannelFactory<IServer>("defaultEndPoint");
IServer channel = factory.CreateChannel();
const int threadCount = 6;
int value = 0;
for (int i = 0; i < threadCount; i++)
{
new Thread(state =>
{
int n;
lock (lockObj)
{
value++;
n = value;
}
Console.WriteLine("Send value = {0}, Time = {1}", n, DateTime.Now.TimeOfDay);
n = channel.GetResult(n);
Console.WriteLine("Response value = {0}, Time = {1}", n, DateTime.Now.TimeOfDay);
}).Start();
}
Console.ReadLine();
}
}
}
服务配置:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="DefaultBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceThrottling maxConcurrentCalls="1000" maxConcurrentInstances="1000" maxConcurrentSessions="1000"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="Server.Server" behaviorConfiguration="DefaultBehavior">
<endpoint contract="Server.IServer" binding="basicHttpBinding" address=""/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:7803/"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup></configuration>
客户端的控制台输出:
发送值= 1,时间= 11:20:13.1335555
发送值= 3,时间= 11:20:13.1335555
发送值= 2,时间= 11:20:13.1335555
发送值= 4,时间= 11:20:13.1335555
发送值= 5,时间= 11:20:13.1335555
发送值= 6,时间= 11:20:13.1335555
响应值= 3,时间= 11:20:14.6191583
响应值= 1,时间= 11:20:15.6184362
响应值= 2,时间= 11:20:16.6342291
响应值= 4,时间= 11:20:17.6497805
响应值= 5,时间= 11:20:18.6657260
响应值= 6,时间= 11:20:19.6820159
服务端的控制台输出:
In:3,时间:11:20:13.5030783,ThreadId:12
Out:3,Time:11:20:14.5184547,ThreadId:12
In:1,Time:11:20:14.6035310,ThreadId:12
Out:1,Time:11:20:15.6184362,ThreadId:12
In:2,Time:11:20:15.6184362,ThreadId:12
Out:2,Time:11:20:16.6342291,ThreadId:12
In:4,Time:11:20:16.6342291,ThreadId:12
Out:4,Time:11:20:17.6497805,ThreadId:12
在:5,时间:11:20:17.6497805,ThreadId:12
Out:5,Time:11:20:18.6657260,ThreadId:12
In:6,时间:11:20:18.6657260,ThreadId:12
Out:6,Time:11:20:19.6820159,ThreadId:12
答案 0 :(得分:0)
我意识到到底出了什么问题。在客户端上,所有线程都使用了一个通道副本。并且有必要在每个线程中创建一个单独的通道。像这样:
ChannelFactory<IServer> factory = new ChannelFactory<IServer>("defaultEndPoint");
// !!! IServer channel = factory.CreateChannel();
const int threadCount = 6;
int value = 0;
for (int i = 0; i < threadCount; i++)
{
new Thread(state =>
{
int n;
lock (lockObj)
{
value++;
n = value;
}
IServer channel = factory.CreateChannel(); // !!!
Console.WriteLine("Send value = {0}, Time = {1}", n, DateTime.Now.TimeOfDay);
n = channel.GetResult(n);
Console.WriteLine(" Response value = {0}, Time = {1}", n, DateTime.Now.TimeOfDay);
}).Start();
}
答案 1 :(得分:0)
这是因为您将在客户端限制为单个客户端实例,这显然不支持基本http绑定的多个并发调用。
这里有两个选项:
通过为每个线程创建一个额外的通道来扩展客户端:
ChannelFactory<IServer> factory = new ChannelFactory<IServer>();
const int threadCount = 6;
int value = 0;
for (int i = 0; i < threadCount; i++)
{
new Thread(state =>
{
IServer channel = factory.CreateChannel();
int n;
lock (lockObj)
{
value++;
n = value;
}
...
切换到似乎以不同方式支持并发的WS绑定(尽管客户端有单个实例,但您可以在服务器上创建多个线程)