PHP中单例类实例方法与静态类方法的性能比较?

8
我对客观分析哪种方法更高效感兴趣:调用单例类的实例方法或静态类的方法。我已经看过这个,所以我不想讨论两者之间的区别或哪种更好。我只关心两者之间的相对性能。提前致谢。
-Mike

1
只是给你个参考,我认为关于为什么更倾向于使用单例模式而不是静态类的更好的一般性答案可以在这里找到:https://dev59.com/rlnUa4cB1Zd3GeqPb531#6829705 - Marco Demaio
1
这篇Stackoverflow帖子提供了不同PHP版本之间的一些很好的基准测试,并对问题给出了一个好的答案。 - Simon East
5个回答

22

7
任何人都可以制作漂亮的图表,但如果没有关于测试设置的信息,这些图表就毫无意义。你至少可以提供一个链接,说明这些数据的来源。 - Gordon
4
我刚刚添加了这篇文章的链接。 - Andreas Linden
2
作为一个附注,测试的作者应当清晰明确地声明他在循环中每次调用 TestSingleton::getInstance()。而在真实世界的应用程序中,Singleton 实例有时会被传递为类方法的参数(这是 Singleton 设计与静态类之间的优势之一[https://dev59.com/rlnUa4cB1Zd3GeqPb531#6829705]),因此这些类不会每次都调用 getInstance(),因为它们已经存储了对 Singleton 对象的引用... - Marco Demaio
1
在现实世界的应用程序中,仍然存在许多对单例 getInstance() 的调用而没有存储任何引用,如果是这种情况,则所做的测试可能是一个很好的模拟。很难说!还有一些测试证明 static 调用比方法调用慢 在 PHP 中 https://dev59.com/VnM_5IYBdhLWcg3wNwUv 但即使在那种情况下,也很难说,这也取决于应用程序的操作 https://dev59.com/VnM_5IYBdhLWcg3wNwUv/php-performance-of-static-methods-vs-functions/7045679#7045679 - Marco Demaio
这个测试是错误的,PHP性能分析并不简单。在这种情况下,您必须在服务器端测量CPU和内存消耗。在一般情况下,您还需要跟踪脚本持续时间、第一个输出字节的启动时间以及最后一个输出字节的时间。还有一个垃圾回收机制,根据GC发生的位置不同,它可能会改变计时。测量整个脚本执行可以提供更准确的估计,考虑到GC。有时静态更快,有时单例更快,有时创建新实例更快! - CoffeDeveloper

18
除非您在一个紧密循环中调用它们(意味着没有其他重要代码,其中调用的开销很大)成千上万次,否则不必担心。差异可能会低于一微秒,因此不值得担心。只需做出最佳架构选择即可...
过早优化是万恶之源...
编辑:对于所有投票者,这里是我写的一篇博客文章,描述了为什么像这样的性能比较几乎没有用处。

完全同意,此外还要补充一点,当涉及到包装可能已经实例化的资源(如套接字流、数据库连接等)时,单例模式的instance()方法的额外开销将被抵消,因为静态函数仍然需要检查资源是否存在并在需要时创建它。 - Wrikken
4
问题与在WordPress中的使用有关;插件是否应该使用静态类来封装钩子或类的实例,以便可以使用成千上万次或更多次。在这种情况下不需要实例,因此我选择了静态,但有些人认为静态方法太慢。我不知道事实是什么,所以来这里找答案。仍然不知道答案... - MikeSchinkel
2
我已经回答了这个问题。我的意思是不要担心它。差异可能非常小。做出更好的架构选择。无论哪种方式,都是微优化,所以不用担心... - ircmaxell
2
这难道不可能是一个学术问题吗? - Chris Tonkinson
5
@Mike 使用WordPress并担心性能问题是一种悖论。 ircmaxell 给了你最明智的建议。如果你真的关心代码的性能,那就对应用程序进行剖析以找出瓶颈所在,而不是仅仅假设它们在你认为的地方。学术上认为 X 比 Y 更快并不能让你的代码运行得更快。 - Gordon
@Gordon,你很好地批判了一个比其他任何平台都有更多用户的平台... - MikeSchinkel

3

在调用单例模式对象的实例方法之前,您需要先获取该实例,这需要进行静态方法调用:

SomeClass::getInstance()->myMethod();
// versus
SomeClass::myMethod();

因此,在函数中第一次访问该对象时,您需要首先进行静态方法调用。由于函数调用从未是免费的,因此最好使方法为静态的。


1

我有点晚加入这个对话,但是刚找到这个问题,我想在我的第一篇SO帖子中分享我的想法。

作为一个快速实验(在阅读zolex链接的文章后),我向文章的基准测试添加了第三个测试用例:

$inst = TestSingleton::getInstance();  
for($i=0;$i<$runs;$i++) $inst->test();

当然,结果并不总是100%一致的,但我发现在运行500,000个调用通过所有三种方法时,上述方法比其他两种方法快2-3秒。

虽然我总是会看到“过早优化”的引用而感到不安,但在这种情况下,我认为它恰如其分。性能差异最多只是微不足道的,并且通常更倾向于更合理的单例使用。


true,但请阅读我的评论在zolex的答案中。您的测试模拟了一个真实世界的应用程序,在这种情况下,单例对象可能作为参数传递给其他类方法(对象注入),在这些情况下,类存储对Singleton对象的引用,并且不需要每次调用getIntance。但是zolex的测试仍然模拟了真实世界的应用程序,其中单例getIntance在代码中的任何地方都被调用,而不需要首先存储引用(当使用不同的单例类时甚至不是一个选项)。因此,两个测试都是正确的!但很难说哪个更好地模拟了真实世界的应用程序。 - Marco Demaio
1
实际上,最准确的说法可能是真实世界的应用程序将是两种单例使用方法的混合体。无论哪种方式,我想要表达的真正观点是,单例并没有被夸大成那么糟糕。 - AndyM84

1
在我之前的测试中,我发现调用静态方法比调用实例方法更快,并且稍微更节省内存...但是单例模式不应仅因为这些原因而被忽视。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接