WCF ClientBase 线程安全吗?
Posted
技术标签:
【中文标题】WCF ClientBase 线程安全吗?【英文标题】:Is WCF ClientBase thread safe? 【发布时间】:2011-06-05 06:03:00 【问题描述】:我已经实现了 ClientBase 以使用 WCF 连接到服务。然后我在通道上调用一个方法来与服务通信。
base.Channel.CalculateSomething();
这个调用线程是安全的还是应该在运行多个线程时锁定它?
谢谢
【问题讨论】:
【参考方案1】:这里答案的后续 cmets 也让我不确定,所以我做了更多的挖掘。这里有一些确凿的证据表明 ClientBase<T>
是线程安全的 - this blog post 讨论了如何使 WCF 服务在多个线程同时使用单个客户端代理的情况下正确执行(粗体重点在原文):
...但是,如果满足以下条件,在 PerCall 服务上将 ConcurrencyMode 设置为 Multiple 可以增加服务的吞吐量:
客户端是多线程的,并从多个线程使用同一个代理调用您的服务。
客户端和服务之间的绑定是具有会话的绑定(例如,netTcpBinding、wsHttpBinding w/Reliable Session、netNamedPipeBinding等)。
此外,这篇文章中的证据似乎与 Brian 关于 WCF 序列化任何多线程请求的额外评论相矛盾。该帖子显示来自单个客户端的多个请求同时运行 - 如果 ConcurrencyMode.Multiple
和 InstanceContextMode.PerCall
被使用。
还有一些关于这种方法的性能影响以及一些替代方案的额外讨论 here。
【讨论】:
虽然通道和由通道创建的客户端是线程安全的,但它们可能不支持同时向线路写入多个消息。 来源:MS docs【参考方案2】:是的,它是线程安全的。但是,您应该知道,当使用相同的 ClientBase
实例从多个线程调用 WCF 时,WCF 将自动序列化 CalculateSomething
的执行。因此,如果您期望CalculateSomething
同时运行,那么您将不得不重新考虑您的设计。查看this answer,了解为CalculateSomething
方法创建异步API 的一种方法。
【讨论】:
您能否解释一下您的意思:“但是,您应该知道,当使用同一个 ClientBase 实例从多个线程调用 CalculateSomething 时,WCF 将自动序列化它的执行。”谢谢! 这意味着 WCF 将按顺序而不是同时进行一个接一个的调用(尽管从编程的角度来看它们似乎是这样做的)。 你有什么证据或理由说它是线程安全的?你怎么知道 CalculateSomething 是自动序列化的:它是由客户端 ClientBase 实例序列化,还是在服务器/实现端序列化?我问是因为the ClientBase class on MSDN 的结尾说它不是线程安全的。 @ChrisW:嗯……你让我怀疑我的回答了。实际上,文档完全与我的回答相矛盾。但是,另一方面,如果我没记错的话,这些调用确实是序列化的。伙计,已经很久了,我对这个问题的回忆和以这种方式做 WCF 充其量是模糊的。【参考方案3】:是的,在通道上调用方法是线程安全的(从客户端的角度来看 - 服务的角度取决于服务的实现)。您可以从多个线程并行调用此方法。甚至自动生成代理也会让您为异步调用创建方法。
【讨论】:
你有什么证据或理由说它是线程安全的?我问是因为the ClientBase class on MSDN 的结尾说它不是线程安全的。 @ChrisW:这可能意味着访问ClientBase
的属性不是线程安全的,但对服务的调用是(或者它可能是文档中的错误——这并不罕见)。首先,您可以在没有客户群的情况下拨打电话——您只需要一个渠道。我没有任何证据。我只是相信调用远程服务不需要存储任何全局共享数据 - 否则 WCF 的整个客户端将设计得非常糟糕。
内部“通道”是否已知是线程安全的?我想一个通道拥有一些内存缓冲区和一个网络套接字;并且除非它被明确设计为支持并发用户(例如通过对他们的请求进行排序),否则如果两个尝试同时写入内存和套接字将是灾难性的。
@ChrisW:Channel 只为特定的传输协议使用通用的 .NET 实现。例如对于 HTTP,它将为每个调用创建一个新的 HttpWebRequest
实例。我坚信进行调用是线程安全的操作,因为每个调用都应该单独处理——可能有一些共享数据,例如安全上下文,但我希望能够处理。更改 ClientBase
上的任何内容可能不是线程安全的 - 另一方面,如果我没记错的话,一些更改只能在您第一次调用之前完成。
在过去的两年里,您是否将“坚信”和“希望”改为“知道” ?最好有一个明确说明这一点的主要来源(如果你有的话)。【参考方案4】:
它可能关注的对象。 WCF 客户端库可以是线程安全的,至少在此配置中是这样。其他配置我没试过。
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IWcfCallbacksContract), Namespace = "http://wcf.applicatin.srv/namespace")]
public interface IWcfContract
[OperationContract]
CompositeReturnObject GetServerObject();
服务:
public CompositeReturnObject GetServerObject()
CompositeReturnObject ret = new CompositeReturnObject("Hello");
Thread.Sleep(10000); // Simulating long call
return ret;
客户:
private void GetData_Click(object sender, RoutedEventArgs e)
Console.WriteLine("Task 1 start: " + DateTime.Now.ToString("HH:mm:ss"));
Task.Factory.StartNew(() =>
var res = _proxy.GetServerObject();
Console.WriteLine("Task 1 finish: " + DateTime.Now.ToString("HH:mm:s"));
Console.WriteLine(res.ToString());
return;
);
Thread.Sleep(2000);
Console.WriteLine("Task 2 start: " + DateTime.Now.ToString("HH:mm:ss"));
Task.Factory.StartNew(() =>
var res = _proxy.GetServerObject();
Console.WriteLine("Task 2 finish: " + DateTime.Now.ToString("HH:mm:s"));
Console.WriteLine(res.ToString());
return;
);
结果:
任务 1 开始时间:15:47:08 任务 2 开始:15:47:10
任务 1 完成时间:15:47:18 名称:对象一“你好”
任务 2 完成时间:15:47:20 名称:对象一“你好”
【讨论】:
这表明调用没有序列化。它无法证明客户端是线程安全的——这可能是巧合。以上是关于WCF ClientBase 线程安全吗?的主要内容,如果未能解决你的问题,请参考以下文章
在哪里存储当前 WCF 调用的数据? ThreadStatic 安全吗?
java priorityblockingqueue 线程安全吗