【问题标题】:Why is an empty __set() method slower than one that does work?为什么空的 __set() 方法比有效的方法慢?
【发布时间】:2014-04-14 00:46:27
【问题描述】:

我正在玩弄 PHP 魔术方法(特别是 Property overloading),并且在进行微基准测试时遇到了一个我无法解释的怪癖:

似乎带有空主体的__set 方法的运行时间比运行有效的方法要多。下面的代码 sn-p 演示了这一点:

class EmptySetter {
    public function __set($name, $value) {}
}

class NonEmptySetter {
    public function __set($name, $value) {
        $this->{$name} = $value;
    }
}

function benchmark($obj) {
    $start_time = microtime(TRUE);
    for ($i = 0; $i < 10000000; $i++) {
        $obj->foo = 42;
    }
    return microtime(TRUE) - $start_time;
}

printf("EmptySetter: %.2f seconds\n", benchmark(new EmptySetter));
printf("NonEmptySetter: %.2f seconds\n", benchmark(new NonEmptySetter));

// output (on my Core 2 Duo laptop):
// EmptySetter: 4.39 seconds
// NonEmptySetter: 1.28 seconds

有人解释为什么会这样吗?

【问题讨论】:

  • 这有关系吗?你曾经获得过 1000 万次连续访问吗?还有,你到底为什么要用空法?基准只有在应用于现实情况时才有意义。这是一个人为的例子。
  • @SverriM.Olsen,没关系,但很有趣:^)
  • @sectus 只有对 PHP 的 C 实现感兴趣时才会感兴趣。性能方面,只有当你使用空的魔法方法 1000 万次时才有用......(以及对我之前评论的更正:我的意思是说“对该方法的连续调用”。我不知道为什么我使用“连续访问” " 为例。)
  • @SverriM.Olsen,所以,这笔交易不在 PHP 的 C 实现中,它是错误的测试实现。

标签: php magic-methods microbenchmark


【解决方案1】:

哦,我知道这是错误的测试用例。

在第一个循环之后NonEmptySetter 将拥有新的公共属性foo。 Next 循环根本不调用__set 方法,它们使用公共属性。

class NonEmptySetter {
    public function __set($name, $value) {
        echo 'called only once'; // would be echoed only once.
        $this->{$name} = $value;
    }
}

有效测试

class EmptySetter {
    public function __set($name, $value) {}
}

class NonEmptySetter {
    public function __set($name, $value) {
        $this->{$name} = $value;
    }
}

function benchmark($class_name) {
    $start_time = microtime(TRUE);
    for ($i = 0; $i < 1000000; $i++) {
        $obj = new $class_name();
        $obj->foo = 42;
    }
    return microtime(TRUE) - $start_time;
}

printf("NonEmptySetter: %.2f seconds\n", benchmark('NonEmptySetter'));
printf("EmptySetter: %.2f seconds\n", benchmark('EmptySetter'));

http://3v4l.org/gVtSq

空设置器更快。

【讨论】:

  • 究竟在什么方面更快? EmptySetter::$foo 不存在。
  • @TOOTSKI,我们不需要检查这段代码的相等性(它们不是)。我刚刚说过,无论他们做什么,第一次代码和平都比第二次快。
【解决方案2】:

你不能比较这两个,因为最终的结果是不相等的。

$o1 = (new NonEmptySetter);
$o1->foo = 42;

$o2 = (new EmptySetter);
$o2->foo = 42;

var_dump($o1, $o2, $o2->foo);

这给出了:

object(NonEmptySetter)[1]
  public 'foo' => int 42

object(EmptySetter)[2]

null

还有最后一个通知:Notice: Undefined property: EmptySetter::$foo

这意味着属性从未设置,它不存在,仙尘,我假设那里的违规行为需要时间。

如果你正确地声明你的类(注意$foo):

class EmptySetter {
    public $foo = NULL;
    public function __set($name, $value) {}
}

时间限制:Your benchmark with EmptySetter::$foo declared

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    • 2011-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多