为什么将 isset 应用于多维数组会使执行时间增加 4000%?

Why applying isset to a multidimensional array increased execution time by 4000%?

编辑: 事实证明,$article->getID(); 是导致超标执行时间的部分。这是它的样子:

public function getId()
{
    return $this->id;
}

但我仍然不知道为什么会这样。


我正在使用此代码尝试为包含 1000 个文档和 4000 个 唯一 个标记的小型语料库中的每个标记计算 document frequency

为此,我编写了这个函数:

public function computeIDF(){
    // splitting documents into tokens
    $this->tokens = $this->tokenize();
    // $this->tokens = array($article->id => array($token => $freq))

    // 1. For each token …
    foreach($this->tokens as $token){

        // 2. … look in every document …
        foreach($this->articles as $article){

            // 3. … and if it exists there …
            if(isset($this->tokens[$article->getID()][$token]){

                // 4. … add 1
                $tokFreq[$token] += 1;
            }
        }
    }
}

但是第 3 步引起了很多麻烦:
- 如果我注释掉步骤 4.,没有任何变化;
- 如果我注释掉步骤 3.,执行时间从 414.2s 变为 "just" 14s,几乎快了 4000% !!1! (所以,这绝对不是 "micro-optimization" 问题。

注意这里不涉及数据库。一切都早早地从整个 class' 范围中获取:

// This is where the data is being fetched
$articles = ArticleDAO::loadLast(1000);

// It's then injected into the $corpus
$corpus = new Corpus($articles);

我是不是做错了什么?如果是这样,我怎样才能使事情变得更快?

每次调用 $article->getID() 都有开销。它必须保存堆栈,调用函数,复制结果,然后恢复。因为您要为每篇文章迭代每个标记(而不是相反),所以每次调用 getID 都将针对不同的文章,因此不能走捷径。

您可以做两件事:

  1. 仅将 $article->getID() 替换为 $article->id
  2. 让你的外循环跨文章,让你的内循环跨令牌。这样你就可以在一篇文章中找到整批令牌,这应该有助于缓存。