WCF服务慢速调用取决于调用方



我已经设置了一个本地WCF服务,使用NetNamedPipeBinding在控制台应用程序中自托管以进行客户端访问。

要调用服务,我引用library.dll,其中我有以下方法:

public static string GetLevel(Point p)
{   
ChannelFactory<IService> pipeFactory = new ChannelFactory<IService>(new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/PTS_Service"));
IService pipeProxy = pipeFactory.CreateChannel();
string result = pipeProxy.GetLevel(p);
((IClientChannel)pipeProxy).Close();
pipeFactory.Close();
}

GetLevel()命令根据点(X,Y,Z(p的Z坐标,从服务中存储的列表中返回一个字符串。

如果从上面的控制台应用程序调用该方法,这将起作用,并且总速度为8ms。

然而,当从另一个app.exeplugin.dll(由外部程序加载(调用来自library.dll的相同方法时,次数急剧增加。我已经停止观看以上5行代码:

  • consoleHost.exe:0-3-6-7-8
  • app.exe:89-155-248-259-271
  • plugin.dll:439-723-1210-1229-1245

时间不应该是一样的吗,而不是取决于谁打电话给library.dll

编辑

由于我已经取消了所有只从运行的服务中检索字符串的方法,我认为问题在于channelFactory的第一次创建运行,在同一个应用程序/插件运行中的所有后续调用在时间上都是相等的。

我知道第一次调用速度较慢,但正如我所看到的,在一个新应用程序中大约是30ms,在我的插件中大约是900ms,我相信这是另一个原因造成的。

我发现了一个类似延迟的问题:在新的AppDomain中建立的第一个WCF连接非常慢,解决方案是将LoaderOptimizationAttribute设置为MultiDomain。有没有可能每次运行插件时都必须JIT编译,而不是使用本机代码?

我尝试在consoleHost.exe中的main上面添加这段代码,但在插件运行时没有看到任何好处。这可能是因为介于两者之间的外部程序吗?有办法解决这个问题吗?比方说,我的插件可以在任何时候创建一个新的Appdomain来访问服务,并在这个新的Appdomain中从我的library.dll调用上面的方法吗?或者这毫无意义吗?

EDIT2

我记录了使用评论中建议的评测程序进行JIT编译所花费的时间,这为JIT编译提供了700毫秒的时间,为插件提供了800毫秒的总执行时间。

我用ngen预编译library.dll来创建一个本机映像.ni.dll。我在process explorer中看到这个映像是由外部程序加载的,尽管插件中没有时间增益?据我所知,插件仍然JIT编译应该没有任何原因,或者我做错了什么?

我还注意到,在VS中调试时,控制台&应用程序只加载一些程序集,插件每次创建或修改插件实例时都会加载和卸载。我相信这就是插件的工作方式,不应该解释第一次执行时间的差异吗?

通信不应该依赖于调用者,而应该依赖于调用的方式。

最耗费时间的操作是创建一个通道。如果代理一旦创建,那么每个下一次调用都将以类似的平均速度完成。(当然,如果呼叫者从同一个地方使用服务:网络中的同一台机器。在您的情况下应该是相同的,而在您的例子中您使用的是localhost(

一些性能提升也可以通过服务配置进行存档(SingleInstance应该比PerCall更快(。

另一个需要注意的点是检查服务方法中可能存在的锁。当服务繁忙时,某些服务客户端可能正在等待呼叫。

如果服务调用不是异步调用,请尝试使其异步并使用它。

经过进一步调查:当进程启动时,外部程序通过.ini文件中的设置阻止共享加载的程序集/JIT编译。幸运的是,这可以被禁用,所以共享也可以在插件中实现。

更改此设置(.ini中的1行设置为"否"而不是"是"!(后,时间减少到30ms,每次通话时间减少到3ms或更短。

最新更新