静态方法与函数的性能

时间:2022-09-25 07:36:52

In PHP, (unlike what i originally thought) there an overhead of calling static methods vs simple functions.

在PHP中(不同于我最初的想法)调用静态方法和简单函数的开销。

On a very simple bench, this overhead is over 30% of the calling time (the method just returns the parameter):

在一个非常简单的工作台上,这个开销超过调用时间的30%(方法只返回参数):

// bench static method
$starttime = microtime(true);
for ($i = 0; $i< 10*1000*1000; $i++)
    SomeClass::doTest($i);

echo "Static Time:   " , (microtime(true)-$starttime) , " ms\n";

// bench object method
$starttime = microtime(true);

for ($i = 0; $i< 10*1000*1000; $i++)
    $someObj->doTest($i);

echo "Object Time:   " , (microtime(true)-$starttime) , " ms\n";

// bench function
$starttime = microtime(true);

for ($i = 0; $i< 10*1000*1000; $i++)
    something_doTest($i);

echo "Function Time: " , (microtime(true)-$starttime) , " ms\n";

outputs:

输出:

Static Time:   0.640204906464 ms
Object Time:   0.48961687088 ms
Function Time: 0.438289880753 ms

I know the actual time is still negligible unless i am actually calling something 1 million times, but the fact is that its there.

我知道实际的时间是可以忽略的除非我实际调用了100万次,但事实上它就在那里。

Will anyone care to try and explain what is happening behind the scenes?

有人愿意尝试解释幕后发生的事情吗?

update:
- added object method bench

更新:-添加对象方法工作台

6 个解决方案

#1


45  

Apparently this point has been fixed in later versions of PHP (5.5.12).

显然,这一点在PHP的后续版本(5.5.12)中得到了修正。

I ran the OP's code (with empty methods), and I get these results :

我运行OP的代码(使用空方法),得到以下结果:

Static Time:   1.0153820514679 ms
Object Time:   1.100515127182 ms

Edit: Eight months and some releases later...

It's interesting to see how Zend and the community are working hard on PHP's performance.

看看Zend和社区如何努力提高PHP的性能是很有趣的。

???? PHP 5.6

Here is the same benchmark with PHP 5.6.9 (ZE 2.6) :

下面是PHP 5.6.9 (ZE 2.6)的相同基准:

Static Time:   0.97488021850586 ms
Object Time:   1.0362110137939 ms
Function Time: 0.96977496147156 ms

For one run, "object time" was even faster than static time, so now they are very close. Better, we can see that objects are almost fast as functions!

一次运行,“对象时间”甚至比静态时间还要快,所以现在它们非常接近了。更好的是,我们可以看到对象几乎是快速的函数!

???? PHP 7.0

I've also compiled PHP 7.0 alpha 1 (ZE 3.0) and it is amazing to see how a fast language like PHP (Compared to other dynamic languages as you can see here or here) can be optimized again and again:

我还编译了PHP 7.0 alpha 1 (ZE 3.0),看到像PHP这样的快速语言(与其他动态语言相比,你可以在这里或这里看到)是如何被不断地优化的,这是令人惊讶的:

Static Time:   0.33447790145874 ms
Object Time:   0.30291485786438 ms
Function Time: 0.2329089641571 ms

With PHP7, basic functions have been greatly optimized, and "static time" is again slower than "instance/object time".

PHP7极大地优化了基本函数,“静态时间”又比“实例/对象时间”慢。

Edit, October 2015 one year later : PHP 7.0 RC5. Now, "static time" is faster. An important thing to note: scalar type hinting (new feature in PHP7) brings a significant overhead, it's about 16% slower (type hinting does not make your code 16% slower, it's that slower when you code is only composed of function calls ;) In real life applications, this is negligible). Such an overhead could seem illogic, but it's less surprizing when you know that dynamic typing is at the core of PHP. Contrarily to other more-static languages, type hinting in PHP means more checks for the Zend Engine, and not less as some of us could expect. In the future, we will probably get more runtime optimizations on this point (exactly like HHVM's runtime code analyses and JiT approach). Do not forget that PHP7 is young, and all the cleanup that has been done for this release permits great enhancements in the future, in features and performance.

编辑,2015年10月1年后:PHP 7.0 RC5。现在,“静态时间”更快了。需要注意的一件重要的事情是:标量类型暗示(PHP7中的新特性)带来了很大的开销,它大约慢了16%(类型暗示不会使代码慢16%,只有当代码由函数调用组成时才会慢;)在实际应用中,这是可以忽略的)。这样的开销似乎不符合逻辑,但当您知道动态类型是PHP的核心时,就不那么奇怪了。与其他更静态的语言相反,在PHP中类型提示意味着对Zend引擎的更多检查,而不是像我们所期望的那样少。将来,我们可能会在这一点上得到更多的运行时优化(就像HHVM的运行时代码分析和JiT方法一样)。不要忘记PHP7还很年轻,并且为这个版本所做的所有清理工作都允许将来在特性和性能上有很大的改进。

???? HHVM

A test against HHVM 3.7.1 still shows that HHVM easily wins on that type of benchmarks, here you can see the benefits of a JiT compilation (JiT is a "planned" feature for future versions of PHP, we'll probably get it in the 7.x or 8.x branches. Zend had created a PoC, as an OpCache extension):

针对HHVM 3.7.1的测试仍然表明,HHVM很容易在这类基准测试中胜出,这里您可以看到JiT编译的好处(JiT是PHP未来版本的“计划”特性,我们可能会在7中得到它。x或8。x分支。Zend创建了一个PoC,作为OpCache扩展):

Static Time:   0.070882797241211 ms
Object Time:   0.23940300941467 ms
Function Time: 0.06760311126709 ms

For HHVM, functions and static methods have a very similar timing, this could let us think that, internally, those are almost the same things (after all, a static method is very similar to a namespaced function). The instance timing is "catastrophic" compared to the others. This shows how HHVM and ZE are very different engines.

对于HHVM来说,函数和静态方法的时间安排非常相似,这可以让我们认为,在内部,它们几乎是相同的东西(毕竟,静态方法与名称空间函数非常相似)。与其他实例相比,实例时间选择是“灾难性的”。这说明了HHVM和ZE是多么不同的引擎。

Conclusion?

There's no guarantee that one of these practices (static/instance) will stay the faster, forever. Use what seems the best in terms of software design and keep a coherent code into an existing application.

不能保证其中一个实践(静态/实例)将永远保持更快。在软件设计方面使用最好的方法,并在现有的应用程序中保持一致的代码。

If you have the choice, and/or if you're writing a library, etc, then maybe you could use instance methods, it's more friendly with DI environments, and that gives more control to the developer that consumes your API.

如果您有选择,或者您正在编写一个库,等等,那么也许您可以使用实例方法,它对DI环境更友好,这将给开发人员更多的控制,从而消耗您的API。

If you're just providing utility functions (like those little packages in npm's ecosystem), then you could use namespaced functions (but be aware that PHP still doesn't have function autoloading, meaning that Composer can't lazy-load your library like it does with PSR-0/4)

如果您只是提供实用功能(比如npm生态系统中的那些小程序包),那么您可以使用名称空间函数(但要注意PHP仍然没有函数自动加载,这意味着编写器不能像使用PSR-0/4那样延迟加载您的库)

#2


23  

There used to be a big penalty when calling a static method - but it's fixed in 5.4.0 - see the extensive test results http://www.micro-optimization.com/global-function-vs-static-method .

在调用静态方法时,通常会有很大的代价——但是在5.4.0中是固定的——请参见http://www.micro-optimization.com/global-function-vs-static-method的大量测试结果。

#3


7  

I repeated the test on my machine multiple times and surprisingly you are right!

我多次在我的机器上重复了这个测试,令人惊讶的是你是对的!

In PHP calling methods of static class seems to be slower than calling object methods. Click here for simple test.

在PHP中,静态类的调用方法似乎比调用对象方法要慢。点击这里进行简单的测试。

The code with the running test is in the above link.

带有运行测试的代码在上面的链接中。

I even tried placing both the objet method and the static method in the same class and the static method still results SLOWER!!!

我甚至尝试将objet方法和静态方法放在同一个类中,静态方法的结果仍然比较慢!!

At this point I'm wondering how slow could be a call to a static method of an inherited class, since inheritance adds up delay.

此时,我想知道调用继承类的静态方法有多慢,因为继承会增加延迟。

Sadly, I'm clueless about the reason. Maybe PHP takes more time in finding the definition of the static method.

遗憾的是,我对原因一无所知。也许PHP在查找静态方法的定义上花费了更多的时间。

As a side note I could only say that in a real life application it usually happens to have the object created before calling one of its methods. Therefor your test should take this into account comparing the loop of static calls to a loop that each time (or at least some times) [*] creates the objet:

作为附带说明,我只能说,在实际应用程序中,通常在调用它的方法之前创建对象。因此,您的测试应该考虑到将静态调用的循环与每次(或至少有时)创建objet的循环进行比较:

for($i=0; $i<10*1000*1000; $i++)
{ 
   $someObj = new someObj();
   $someObj->doTest($i); 
}

thus is obviously slower than the static call.

因此显然比静态调用要慢。

for($i=0; $i<10*1000*1000; $i++)
{ 
   SomeClass::doTest($i);
}

[*] the problem is: how much is some times in order to simulate what happnes in a real world app? It's hard to say!

[*]问题是:为了模拟真实世界的应用程序中发生的事情,有时候需要花费多少时间?很难说!

#4


6  

There is some thing Wrong in your tests. With a website designed to work with multiple users at the same time you have to create an object for each one. To run that object's method in your tests you should have:

你的考试中出了点问题。如果网站设计为同时与多个用户一起工作,您必须为每个用户创建一个对象。要在测试中运行该对象的方法,您应该拥有:

for($i=0; $i<10*1000*1000; $i++)
{ 
   $someObj = new someObj();
   $someObj->doTest($i); 
}

If your object had more properties and methods then creating it is slower and PHP uses more memory. A static method won't have this problem, and therefore using static methods is a better choice in lots of situations. For example, a class with some handy tools with static methods for common tasks.

如果您的对象有更多的属性和方法,那么创建它会更慢,PHP会使用更多的内存。静态方法不会有这个问题,因此在很多情况下使用静态方法是更好的选择。例如,一个具有一些便利工具的类,其中包含用于公共任务的静态方法。

#5


2  

It has been a while since I have done any PHP but this is probably similar to what you expect in other programming environments.

我已经有一段时间没有使用PHP了,但这可能与您在其他编程环境中所期望的类似。

It is likely that the static method requires some construction of a SomeClass object behind the scenes each time that it is called, whereas the function can just be executed without any startup cost. Creating an object could be costly depending on a number of things: destruction of existing objects by a garbage collector/reference counter, memory pressure causing fragmentation, suboptimal memory allocation policies in the C runtime etc.

很可能静态方法每次调用时都需要在幕后构建SomeClass对象,而函数可以在不需要启动成本的情况下执行。创建对象的成本可能会很高,这取决于许多因素:垃圾收集器/引用计数器破坏现有对象、导致碎片的内存压力、C运行时的次优内存分配策略等等。

It would be interesting to compare the method performance of an existing object. To do this create an instance of SomeClass and then call an instance method repeatedly.

比较现有对象的方法性能是很有趣的。为此,创建一个SomeClass的实例,然后重复调用一个实例方法。

#6


2  

In the case of the static method, PHP has to check wether the method can or cannot be called from the calling context (public, protected, private). That's most likely what causes the overhead, or at least part of it, since the classic function call doesn't require PHP to perform that kind of check.

在静态方法的情况下,PHP必须检查是否可以从调用上下文(public、protected、private)调用该方法。这很可能是导致开销的原因,或者至少是部分原因,因为经典的函数调用不需要PHP来执行这种检查。

#1


45  

Apparently this point has been fixed in later versions of PHP (5.5.12).

显然,这一点在PHP的后续版本(5.5.12)中得到了修正。

I ran the OP's code (with empty methods), and I get these results :

我运行OP的代码(使用空方法),得到以下结果:

Static Time:   1.0153820514679 ms
Object Time:   1.100515127182 ms

Edit: Eight months and some releases later...

It's interesting to see how Zend and the community are working hard on PHP's performance.

看看Zend和社区如何努力提高PHP的性能是很有趣的。

???? PHP 5.6

Here is the same benchmark with PHP 5.6.9 (ZE 2.6) :

下面是PHP 5.6.9 (ZE 2.6)的相同基准:

Static Time:   0.97488021850586 ms
Object Time:   1.0362110137939 ms
Function Time: 0.96977496147156 ms

For one run, "object time" was even faster than static time, so now they are very close. Better, we can see that objects are almost fast as functions!

一次运行,“对象时间”甚至比静态时间还要快,所以现在它们非常接近了。更好的是,我们可以看到对象几乎是快速的函数!

???? PHP 7.0

I've also compiled PHP 7.0 alpha 1 (ZE 3.0) and it is amazing to see how a fast language like PHP (Compared to other dynamic languages as you can see here or here) can be optimized again and again:

我还编译了PHP 7.0 alpha 1 (ZE 3.0),看到像PHP这样的快速语言(与其他动态语言相比,你可以在这里或这里看到)是如何被不断地优化的,这是令人惊讶的:

Static Time:   0.33447790145874 ms
Object Time:   0.30291485786438 ms
Function Time: 0.2329089641571 ms

With PHP7, basic functions have been greatly optimized, and "static time" is again slower than "instance/object time".

PHP7极大地优化了基本函数,“静态时间”又比“实例/对象时间”慢。

Edit, October 2015 one year later : PHP 7.0 RC5. Now, "static time" is faster. An important thing to note: scalar type hinting (new feature in PHP7) brings a significant overhead, it's about 16% slower (type hinting does not make your code 16% slower, it's that slower when you code is only composed of function calls ;) In real life applications, this is negligible). Such an overhead could seem illogic, but it's less surprizing when you know that dynamic typing is at the core of PHP. Contrarily to other more-static languages, type hinting in PHP means more checks for the Zend Engine, and not less as some of us could expect. In the future, we will probably get more runtime optimizations on this point (exactly like HHVM's runtime code analyses and JiT approach). Do not forget that PHP7 is young, and all the cleanup that has been done for this release permits great enhancements in the future, in features and performance.

编辑,2015年10月1年后:PHP 7.0 RC5。现在,“静态时间”更快了。需要注意的一件重要的事情是:标量类型暗示(PHP7中的新特性)带来了很大的开销,它大约慢了16%(类型暗示不会使代码慢16%,只有当代码由函数调用组成时才会慢;)在实际应用中,这是可以忽略的)。这样的开销似乎不符合逻辑,但当您知道动态类型是PHP的核心时,就不那么奇怪了。与其他更静态的语言相反,在PHP中类型提示意味着对Zend引擎的更多检查,而不是像我们所期望的那样少。将来,我们可能会在这一点上得到更多的运行时优化(就像HHVM的运行时代码分析和JiT方法一样)。不要忘记PHP7还很年轻,并且为这个版本所做的所有清理工作都允许将来在特性和性能上有很大的改进。

???? HHVM

A test against HHVM 3.7.1 still shows that HHVM easily wins on that type of benchmarks, here you can see the benefits of a JiT compilation (JiT is a "planned" feature for future versions of PHP, we'll probably get it in the 7.x or 8.x branches. Zend had created a PoC, as an OpCache extension):

针对HHVM 3.7.1的测试仍然表明,HHVM很容易在这类基准测试中胜出,这里您可以看到JiT编译的好处(JiT是PHP未来版本的“计划”特性,我们可能会在7中得到它。x或8。x分支。Zend创建了一个PoC,作为OpCache扩展):

Static Time:   0.070882797241211 ms
Object Time:   0.23940300941467 ms
Function Time: 0.06760311126709 ms

For HHVM, functions and static methods have a very similar timing, this could let us think that, internally, those are almost the same things (after all, a static method is very similar to a namespaced function). The instance timing is "catastrophic" compared to the others. This shows how HHVM and ZE are very different engines.

对于HHVM来说,函数和静态方法的时间安排非常相似,这可以让我们认为,在内部,它们几乎是相同的东西(毕竟,静态方法与名称空间函数非常相似)。与其他实例相比,实例时间选择是“灾难性的”。这说明了HHVM和ZE是多么不同的引擎。

Conclusion?

There's no guarantee that one of these practices (static/instance) will stay the faster, forever. Use what seems the best in terms of software design and keep a coherent code into an existing application.

不能保证其中一个实践(静态/实例)将永远保持更快。在软件设计方面使用最好的方法,并在现有的应用程序中保持一致的代码。

If you have the choice, and/or if you're writing a library, etc, then maybe you could use instance methods, it's more friendly with DI environments, and that gives more control to the developer that consumes your API.

如果您有选择,或者您正在编写一个库,等等,那么也许您可以使用实例方法,它对DI环境更友好,这将给开发人员更多的控制,从而消耗您的API。

If you're just providing utility functions (like those little packages in npm's ecosystem), then you could use namespaced functions (but be aware that PHP still doesn't have function autoloading, meaning that Composer can't lazy-load your library like it does with PSR-0/4)

如果您只是提供实用功能(比如npm生态系统中的那些小程序包),那么您可以使用名称空间函数(但要注意PHP仍然没有函数自动加载,这意味着编写器不能像使用PSR-0/4那样延迟加载您的库)

#2


23  

There used to be a big penalty when calling a static method - but it's fixed in 5.4.0 - see the extensive test results http://www.micro-optimization.com/global-function-vs-static-method .

在调用静态方法时,通常会有很大的代价——但是在5.4.0中是固定的——请参见http://www.micro-optimization.com/global-function-vs-static-method的大量测试结果。

#3


7  

I repeated the test on my machine multiple times and surprisingly you are right!

我多次在我的机器上重复了这个测试,令人惊讶的是你是对的!

In PHP calling methods of static class seems to be slower than calling object methods. Click here for simple test.

在PHP中,静态类的调用方法似乎比调用对象方法要慢。点击这里进行简单的测试。

The code with the running test is in the above link.

带有运行测试的代码在上面的链接中。

I even tried placing both the objet method and the static method in the same class and the static method still results SLOWER!!!

我甚至尝试将objet方法和静态方法放在同一个类中,静态方法的结果仍然比较慢!!

At this point I'm wondering how slow could be a call to a static method of an inherited class, since inheritance adds up delay.

此时,我想知道调用继承类的静态方法有多慢,因为继承会增加延迟。

Sadly, I'm clueless about the reason. Maybe PHP takes more time in finding the definition of the static method.

遗憾的是,我对原因一无所知。也许PHP在查找静态方法的定义上花费了更多的时间。

As a side note I could only say that in a real life application it usually happens to have the object created before calling one of its methods. Therefor your test should take this into account comparing the loop of static calls to a loop that each time (or at least some times) [*] creates the objet:

作为附带说明,我只能说,在实际应用程序中,通常在调用它的方法之前创建对象。因此,您的测试应该考虑到将静态调用的循环与每次(或至少有时)创建objet的循环进行比较:

for($i=0; $i<10*1000*1000; $i++)
{ 
   $someObj = new someObj();
   $someObj->doTest($i); 
}

thus is obviously slower than the static call.

因此显然比静态调用要慢。

for($i=0; $i<10*1000*1000; $i++)
{ 
   SomeClass::doTest($i);
}

[*] the problem is: how much is some times in order to simulate what happnes in a real world app? It's hard to say!

[*]问题是:为了模拟真实世界的应用程序中发生的事情,有时候需要花费多少时间?很难说!

#4


6  

There is some thing Wrong in your tests. With a website designed to work with multiple users at the same time you have to create an object for each one. To run that object's method in your tests you should have:

你的考试中出了点问题。如果网站设计为同时与多个用户一起工作,您必须为每个用户创建一个对象。要在测试中运行该对象的方法,您应该拥有:

for($i=0; $i<10*1000*1000; $i++)
{ 
   $someObj = new someObj();
   $someObj->doTest($i); 
}

If your object had more properties and methods then creating it is slower and PHP uses more memory. A static method won't have this problem, and therefore using static methods is a better choice in lots of situations. For example, a class with some handy tools with static methods for common tasks.

如果您的对象有更多的属性和方法,那么创建它会更慢,PHP会使用更多的内存。静态方法不会有这个问题,因此在很多情况下使用静态方法是更好的选择。例如,一个具有一些便利工具的类,其中包含用于公共任务的静态方法。

#5


2  

It has been a while since I have done any PHP but this is probably similar to what you expect in other programming environments.

我已经有一段时间没有使用PHP了,但这可能与您在其他编程环境中所期望的类似。

It is likely that the static method requires some construction of a SomeClass object behind the scenes each time that it is called, whereas the function can just be executed without any startup cost. Creating an object could be costly depending on a number of things: destruction of existing objects by a garbage collector/reference counter, memory pressure causing fragmentation, suboptimal memory allocation policies in the C runtime etc.

很可能静态方法每次调用时都需要在幕后构建SomeClass对象,而函数可以在不需要启动成本的情况下执行。创建对象的成本可能会很高,这取决于许多因素:垃圾收集器/引用计数器破坏现有对象、导致碎片的内存压力、C运行时的次优内存分配策略等等。

It would be interesting to compare the method performance of an existing object. To do this create an instance of SomeClass and then call an instance method repeatedly.

比较现有对象的方法性能是很有趣的。为此,创建一个SomeClass的实例,然后重复调用一个实例方法。

#6


2  

In the case of the static method, PHP has to check wether the method can or cannot be called from the calling context (public, protected, private). That's most likely what causes the overhead, or at least part of it, since the classic function call doesn't require PHP to perform that kind of check.

在静态方法的情况下,PHP必须检查是否可以从调用上下文(public、protected、private)调用该方法。这很可能是导致开销的原因,或者至少是部分原因,因为经典的函数调用不需要PHP来执行这种检查。