简介:我相信最佳实践是在您即将使用 Web 服务客户端时实例化它,然后让它超出范围并收集垃圾。这反映在您看到的来自 Microsoft 的示例中。理由如下...
完整:我发现的过程的最佳完整描述是如何:从 Silverlight 访问服务。此处的示例显示了实例化 Web 服务客户端并允许其超出范围(无需关闭它)的典型模式。Web 服务客户端从 ClientBase 继承,后者有一个 Finalize 方法,当对象被垃圾回收时,该方法应在必要时释放任何非托管资源。
我有大量使用 Web 服务的经验,我使用代理并在使用前将它们实例化,然后允许它们被垃圾收集。我从来没有遇到过这种方法的问题。我在Wenlong Dong 的博客上看到说创建代理很昂贵,但即使他说 .NET 3.5 中的性能也有所提高(也许从那以后又有所提高?)。我可以告诉您的是,性能是一个相对术语,除非您检索的数据大小不那么重要,否则在序列化/反序列化和传输方面将花费比创建连接更多的时间。这当然是我的经验,你最好先在这些领域进行优化。
最后,由于我认为到目前为止我的意见可能不够,我写了一个快速测试。我使用 Visual Web Developer 2010 Express 提供的模板创建了启用 Silverlight 的 Web 服务(使用名为 的默认 void 方法DoWork()
)。然后在我的示例 Silverlight 客户端中,我使用以下代码调用它:
int counter=0;
public void Test()
{
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
client.DoWorkCompleted += (obj, args) =>
{
counter++;
if (counter > 9999)
{
for(int j=0;j<10;j++) GC.Collect();
System.Windows.MessageBox.Show("Completed");
}
};
client.DoWorkAsync();
}
for(int i=0;i<10000;i++) Test();
然后我使用并启动了应用程序调用了测试方法。加载应用程序并完成 Web 服务调用(全部 10,000 个)花费了 20 多秒。在进行 Web 服务调用时,我看到该进程的内存使用量跃升至 150MB 以上,但一旦调用完成GC.Collect()
并被调用,内存使用量下降到不到该数量的一半。它远不是一个完美的测试,它似乎向我确认没有内存泄漏,或者它可以忽略不计(考虑到调用 10,000 个 Web 服务调用都使用单独的客户端实例可能并不常见)。此外,它是一个比保留代理对象并不必担心它会出现故障并不得不重新打开它的模型要简单得多。
测试方法的理由:
我的测试集中在两个潜在的问题上。一个是内存泄漏,另一个是创建和销毁对象所花费的处理器时间。我的建议是遵循提供课程的公司(Microsoft)提供的示例是安全的。如果您担心网络效率,那么您应该对我的示例没有问题,因为正确创建/处置这些对象不会影响网络延迟。如果花费 99% 的时间是网络时间,那么优化 1% 的理论改进可能在开发时间方面是浪费的(假设甚至可以获得好处,我相信我的测试清楚地表明几乎没有/没有任何)。是的,网络调用是本地的,也就是说,在 10,000 次服务调用过程中,等待对象的时间只有大约 20 秒。这表示每个服务调用花费在创建对象上的时间约为 2 毫秒。关于调用 Dispose 的必要性,我并不是要暗示你不应该调用它,只是它似乎没有必要。如果你忘记了(或者只是选择不忘记),我的测试让我相信在 Finalize 中为这些对象调用了 Dispose。即便如此,自己调用 Dispose 可能会更有效,但效果仍然可以忽略不计。对于大多数软件开发而言,提出更有效的算法和数据结构比解决此类问题(除非存在严重的内存泄漏)获得更多收益。如果您需要更高的效率,那么也许您不应该使用 Web 服务,因为有比基于 XML 的系统更有效的数据传输选项。