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.MultipleInstanceContextMode.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 安全吗?

c++ string线程安全吗

java priorityblockingqueue 线程安全吗

mongodatabase mongocollection 线程安全吗

可以从多个线程等待相同的任务 - 等待线程安全吗?

可以从多个线程等待相同的任务 - 等待线程安全吗?