我已经实现了ClientBase来使用WCF连接到一个服务。然后我调用通道上的一个方法与服务进行通信。
base.Channel.CalculateSomething();
当运行多个线程时,这个调用是线程安全的吗?还是需要在其周围加锁?
谢谢。
我已经实现了ClientBase来使用WCF连接到一个服务。然后我调用通道上的一个方法与服务进行通信。
base.Channel.CalculateSomething();
当运行多个线程时,这个调用是线程安全的吗?还是需要在其周围加锁?
谢谢。
是的,它是线程安全的。然而,你需要知道当使用相同的ClientBase
实例从多个线程调用CalculateSomething
时,WCF会自动序列化CalculateSomething
的执行。所以,如果你希望CalculateSomething
并发运行,那么你就需要重新考虑你的设计。查看这个答案来了解一种为CalculateSomething
方法创建异步API的方法。
ClientBase<T>
是线程安全的 - 这篇博客文章 讨论了如何使 WCF 服务在存在多个线程同时使用单个客户端代理时正常运行(粗体强调是原文):
此外,这篇文章中的证据似乎与 Brian 的额外评论相矛盾,即 WCF 会序列化任何多线程请求。如果使用了... 然而有一种情况,当 PerCall 服务上的 ConcurrencyMode 设置为 Multiple 时,可以增加您的服务吞吐量,如果满足以下条件:
客户端是多线程的,并且从多个线程使用同一个代理对您的服务进行调用。
客户端和服务之间的绑定是具有会话的绑定(例如 netTcpBinding、具有可靠会话的 wsHttpBinding,netNamedPipeBinding 等)。
ConcurrencyMode.Multiple
和 InstanceContextMode.PerCall
,则该文章显示单个客户端的多个请求可以同时运行。是的,在通道上调用该方法是线程安全的(从客户端的角度来看——服务方面取决于服务实现)。您可以同时从多个线程中调用此方法。即使自动生成代理,也会为您提供创建异步调用方法的选项。
ClientBase
的属性不是线程安全的,但对服务的调用是(或者文档中可能存在错误 - 这并不罕见)。首先,您可以在没有客户端基础的情况下进行调用 - 您只需要一个通道。我没有任何证据。我只是相信调用远程服务不需要存储任何全局共享数据 - 否则,整个WCF客户端端将设计得非常糟糕。 - Ladislav MrnkaHttpWebRequest
实例。我坚信进行调用是线程安全的操作,因为每个调用应该在隔离中处理 - 可能存在一些共享数据,例如安全上下文,但我希望这已经处理好了。更改ClientBase
上的任何内容可能不是线程安全的 - 另一方面,如果我记得正确,有些更改只能在您进行第一次调用之前完成。 - Ladislav Mrnka[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
名称:对象一“你好”