Dad*_*oid 5 c# wcf task-parallel-library
我正在测试WCF并发性和实例化。
有wcf服务:
public class Service1 : IService1
{
public string GetData(int value)
{
Thread.Sleep(1000);
return string.Format("You entered: {0}", value);
}
}
Run Code Online (Sandbox Code Playgroud)
在我的表单应用程序中,我调用了此服务方法。当我进行一次通话时,大约需要1秒钟。
private void single_Click(object sender, EventArgs e)
{
using (var service = new Service1Client())
{
var sw = new Stopwatch();
sw.Start();
service.GetData(1);
sw.Stop();
Debug.WriteLine(sw.Elapsed);
}
}
Run Code Online (Sandbox Code Playgroud)
但是,当我使用Tasks多次调用它时,它需要一个近似值:调用计数* 1秒。
private void mult_Click(object sender, EventArgs e)
{
using (var service = new Service1Client())
{
var tasks = new List<Task<string>>();
for (var i = 0; i < 5; i++)
{
int p = i;
tasks.Add(Task.Factory.StartNew(() => service.GetData(p)));
}
var sw = new Stopwatch();
sw.Start();
Task.WaitAll(tasks.ToArray());
sw.Stop();
Debug.WriteLine(sw.Elapsed);
foreach (var task in tasks)
{
Debug.WriteLine(task.Result);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我已经尝试了实例和并发的所有9种组合(Instance mode = Per Call and Concurrency = Single等)
有趣的是,如果我为所有Task创建新的ServiceClient对象,则可以正常工作,但我认为这不是正确的方法。我觉得一定有一些我想念的东西,如果是的话,你能告诉我到底是什么吗?
问题出在客户端。
在对服务进行任何调用之前,您必须显式调用Open()该Service1Client对象。否则,您的 WCF 客户端代理将在内部调用EnsureOpened(). 问题特别是EnsureOpened()会导致每个请求在执行之前等待前一个请求完成,这就是为什么一次只发送一个请求而不是根据需要并行发送。
像这样改变你的代码:
using (var service = new Service1Client())
{
service.Open();
// Do stuff...
}
Run Code Online (Sandbox Code Playgroud)
来自Wenlong Dong关于该主题的优秀博客文章:
如果您不先调用“Open”方法,则代理将在第一次调用代理时在内部打开。这称为自动打开。为什么?当第一条消息通过自动打开的代理发送时,会导致代理自动打开。您可以使用 .NET Reflector 打开方法 System.ServiceModel.Channels.ServiceChannel.Call 并查看以下代码:
Run Code Online (Sandbox Code Playgroud)if (!this.explicitlyOpened) { this.EnsureDisplayUI(); this.EnsureOpened(rpc.TimeoutHelper.RemainingTime()); }当您深入到EnsureOpened 时,您将看到它调用CallOnceManager.CallOnce。对于非首次调用,您可以点击 SyncWait.Wait 等待第一个请求完成。这种机制是为了保证所有的请求都等待代理打开,同时也保证了正确的执行顺序。因此,所有请求都被序列化为单个执行序列,直到所有请求从队列中排出。在大多数情况下,这不是理想的行为。
| 归档时间: |
|
| 查看次数: |
3114 次 |
| 最近记录: |