如果我有这样定义的服务:
[ServiceContract(SessionMode = SessionMode.NotAllowed)]
public interface IMyService
{
[OperationContract(IsOneWay = true)]
[ReceiveContextEnabled(ManualControl = true)]
void DoSomething(Message<XElement> message);
}我想从我的客户端异步调用它(使用共享契约,而不是从svcutil或添加服务引用生成),我可以这样做:
Task task = Task.Factory.StartNew(() => myService.DoSomething(message));
... some other code
task.Wait();我也可以将我的服务定义为异步的:
[ServiceContract(SessionMode = SessionMode.NotAllowed)]
public interface ICacheKeyExchangeAsync
{
[OperationContract(IsOneWay = true, AsyncPattern = true)]
[ReceiveContextEnabled(ManualControl = true)]
IAsyncResult BeginDoSomething(Message<XElement> message, AsyncCallback callback, object state);
void EndDoSomething(IAsyncResult result);
}并改为这样做
IAsyncResult result = myService.BeginDoSomething(message, null, null);
.... some other code
myService.EndDoSomething(result);这两种方法之间有显著差异吗?
发布于 2013-06-29 21:29:04
是的,Thread Pool线程使用率存在差异。
CLR线程池将线程拆分为两种类型: worker和I/O (您可以在Simple description of worker and I/O threads in .NET和MSDN上找到有关它们的更多信息)。一般而言,线程池为每个核心提供250个工作线程和1000个I/O线程,因此您可以使用工作线程来处理您的WCF服务输入,并使用I/O线程等待异步发送/接收操作完成(这是由overlapped I/O机制在Windows操作系统级别支持的)。
记住上面的内容,让我们通过使用ThreadPool.GetAvailableThreads()方法来看看这两种方法都使用了哪些线程:
int worker;
int ioCompletion;
ThreadPool.GetAvailableThreads(out worker, out ioCompletion);
Console.WriteLine("{0} worker and {1} I/O threads are available", worker, ioCompletion);我将只展示客户端的线程池利用率结果,但对于服务器端也是如此。
用于单向操作的WCF方法。
对于WCF合同:
[ServiceContract]
public interface IService1
{
[OperationContract(IsOneWay = true, AsyncPattern = true)]
IAsyncResult BeginDoSomething(int value, AsyncCallback callback, object state);
void EndDoSomething(IAsyncResult result);
}让我们使用下面的代码将100个请求从客户端发送到服务器:
ChannelFactory<IService1> channelFactory = new ChannelFactory<IService1>();
var client = channelFactory.CreateChannel();
for (int i = 0; i < 100; i++)
{
int worker;
int ioCompletion;
ThreadPool.GetAvailableThreads(out worker, out ioCompletion);
Console.WriteLine("{0} worker and {1} I/O threads are available", worker, ioCompletion);
client.BeginDoSomething(i, asyncCallback, null);
}输出为:
1023 worker and 1000 I/O threads are available
1023 worker and 998 I/O threads are available
1023 worker and 996 I/O threads are available
1023 worker and 996 I/O threads are available
1023 worker and 996 I/O threads are available
1023 worker and 998 I/O threads are available
1023 worker and 998 I/O threads are available
1023 worker and 999 I/O threads are available
1023 worker and 998 I/O threads are available
1023 worker and 998 I/O threads are available
1023 worker and 998 I/O threads are available
1023 worker and 999 I/O threads are available
1023 worker and 999 I/O threads are available
1023 worker and 999 I/O threads are available
1023 worker and 998 I/O threads are available
1023 worker and 998 I/O threads are available
1023 worker and 998 I/O threads are available
1023 worker and 999 I/O threads are available如您所见,我的x4核心机器上的所有工作线程都可用,并且正在使用几个I/O线程。
作为第三方任务运行同步单向操作的。
对于WCF合同:
[ServiceContract]
public interface IService2
{
[OperationContract(IsOneWay = true)]
void DoSomething(int value);
}让我们使用下面的代码运行100个从客户端到服务器的请求(只想注意到TPL在底层使用CLR ThreadPool ):
for (int i = 0; i < 100; i++)
{
int worker;
int ioCompletion;
ThreadPool.GetAvailableThreads(out worker, out ioCompletion);
Console.WriteLine("{0} worker and {1} I/O threads are available", worker, ioCompletion);
Task.Run(() => client.DoSomething(i));
}输出为:
1023 worker and 1000 I/O threads are available
1022 worker and 1000 I/O threads are available
1021 worker and 1000 I/O threads are available
1020 worker and 1000 I/O threads are available
1019 worker and 1000 I/O threads are available
1019 worker and 1000 I/O threads are available
1019 worker and 1000 I/O threads are available
1019 worker and 1000 I/O threads are available
1019 worker and 1000 I/O threads are available
1019 worker and 1000 I/O threads are available
1019 worker and 1000 I/O threads are available
1019 worker and 1000 I/O threads are available
1019 worker and 1000 I/O threads are available
1019 worker and 1000 I/O threads are available
1019 worker and 1000 I/O threads are available
1019 worker and 1000 I/O threads are available
1019 worker and 1000 I/O threads are available
1019 worker and 1000 I/O threads are available
1019 worker and 1000 I/O threads are available
1019 worker and 1000 I/O threads are available正如您所看到的,现在正在利用工作线程,而不是I/O线程。
那么,推荐的方法是什么呢?
总而言之,您的解决方案应该:
bottlenecks;
因此,推荐的方法是Task-based asynchronous pattern for WCF,它满足上述所有要求。
用于WCF.的基于任务的异步模式
对于合同:
[ServiceContract]
public interface IService3
{
[OperationContract(IsOneWay = true)]
Task DoSomethingAsync(int value);
}让我们再次发送100个请求:
for (int i = 0; i < 100; i++)
{
int worker;
int ioCompletion;
ThreadPool.GetAvailableThreads(out worker, out ioCompletion);
Console.WriteLine("{0} worker and {1} I/O threads are available", worker, ioCompletion);
client.DoSomethingAsync(i);
}输出:
1023 worker and 1000 I/O threads are available
1023 worker and 998 I/O threads are available
1023 worker and 999 I/O threads are available
1023 worker and 998 I/O threads are available
1023 worker and 999 I/O threads are available
1023 worker and 998 I/O threads are available
1023 worker and 998 I/O threads are available
1023 worker and 999 I/O threads are available
1023 worker and 999 I/O threads are available
1023 worker and 998 I/O threads are available
1023 worker and 999 I/O threads are available
1023 worker and 998 I/O threads are available
1023 worker and 999 I/O threads are available发布于 2013-06-27 16:55:45
OneWay = true
如果使用OneWay属性,客户端将不会等待服务完成方法的执行。您可以通过创建一个除了等待之外什么都不做的服务方法来轻松地测试。客户端将调用服务方法(即使是同步的),然后继续执行。
您可以通过在您的服务中编写一个简单的测试方法来非常容易地进行测试:
public void Test()
{
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(30));
}并检查当您使用和不使用OneWay属性调用它时的行为。因此,异步调用OneWay方法有些毫无意义,尽管我怀疑这样做意味着将非常小的事情(如创建请求和发送任何数据)推送到另一个线程,因此它可能仍然有用。
AsyncPattern = true
如果您希望客户端等待操作结束(例如,在它启动另一个操作之前),这是很有用的。在OneWay的情况下,客户端将发送一个请求并忘记它-它不关心发生了什么。对于AsyncPattern,当服务完成方法的执行时,客户端将等待通知。
该模式还有一个额外的好处--如果您需要的话,它允许您在方法完成对服务的执行时运行一些代码。例如,在创建需要管理客户端处理程序并在某些事件发生时向客户端发送通知的DuplexService时,它很有用。
PS。关于你的帖子中的这一部分:“使用不是从svcutil生成的共享契约或添加服务引用”,我有点不确定。我认为这对我的回答无关紧要,但以防万一,我在这里留下了这份免责声明。;)
https://stackoverflow.com/questions/17322917
复制相似问题