PHP的yield 乙個以時間換空間的方法

2021-10-25 02:28:45 字數 1636 閱讀 4610

今天在閒逛php的官方文件的時候,發現了這麼個用法:yield,叫生成器

官方是這麼描述的

(php 5 >= 5.5.0, php 7)

生成器提供了一種更容易的方法來實現簡單的物件迭代,相比較定義類實現 iterator 介面的方式,效能開銷和複雜性大大降低。

生成器允許你在 foreach **塊中寫**來迭代一組資料而不需要在記憶體中建立乙個陣列, 那會使你的記憶體達到上限,或者會佔據可觀的處理時間。相反,你可以寫乙個生成器函式,就像乙個普通的自定義函式一樣, 和普通函式只返回一次不同的是, 生成器可以根據需要 yield 多次,以便生成需要迭代的值。

乙個簡單的例子就是使用生成器來重新實現 range() 函式。 標準的 range() 函式需要在記憶體中生成乙個陣列包含每乙個在它範圍內的值,然後返回該陣列, 結果就是會產生多個很大的陣列。 比如,呼叫 range(0, 1000000) 將導致記憶體占用超過 100 mb。

做為一種替代方法, 我們可以實現乙個 xrange() 生成器, 只需要足夠的記憶體來建立 iterator 物件並在內部跟蹤生成器的當前狀態,這樣只需要不到1k位元組的記憶體。

果然還是完全看不懂在說什麼。看下官方的示例**吧:

/*

* for the protection from the leaking of resources

* see rfc

* and use finnaly

*///sample code

function

getlines

($file)}

finally

}foreach

(getlines

("file.txt")as

$n=>

$line

)

簡而言之呢,就是如果在某個函式中使用了生成器yield那麼這個這個函式會被推遲到實際被foreach語句迭代的時候才會被呼叫。

官方的描述是會大量節省記憶體,提高記憶體。我心想這是神器啊!但是轉念一想,如果真的這麼好用,為啥卻沒有被大規模使用呢?是出反常必有妖。

下面測試一下:

傳統寫法如下:

function

test()

}foreach

(test()

as$value

)

然後看執行時間和記憶體占用是:

使用生成器的寫法:

function

test()

}foreach

(test()

as$value

)

再看下執行的時間與消耗的記憶體:

emmmm… 傳統寫法因為會一次性先把資料存入記憶體,所以占用記憶體比較大。而yield的寫法,則可以有效節約記憶體。但是相對應的代價就是:時間消耗大約是傳統寫法的十倍

看來yield只適合處理較大資料例如數g的**之類的,明顯對記憶體造成了過大的壓力情況下才去使用。在資料量比較小的情況下,還是不要使用了。至於背後的原理,則不是本身討論的內容了(我不會說是因為我也不知道)。

以空間換時間的計數排序

我們前面學習的插入 歸併 堆和快速排序都是比較排序,即在排序的最終結果中,各元素的次序依賴於它們之間的比較。我們說過比較排序有時間下界,即nlgn,如果我們需要乙個時間複雜度為o n 的排序演算法,要怎麼辦?計數排序就是比較好的選擇。計數排序的基本思想是 對每乙個輸入的元素x,確定小於x的元素個數。...

C 乙個特殊的迭代語句 yield

yield 在語句中使用該關鍵字,表示出現的方法 運算子或者getter訪問器是乙個迭代器,使用 yield定義迭代器不需要額外的顯示定義型別 依次返回每乙個元素 yield return 語句結束迭代 yield break 返回型別必須為ienumerable,ienumerable,ienum...

yield 乙個很有趣的關鍵字

在偶然的機會下發現了這個關鍵字yield,它的作用是在乙個迴圈體 例如 foreach,for 內部 與return 一起做輸出.要注意的是yield return 所在函式的返回值為ienumerable介面型別 下面實現的是從一堆資料中找出大於特定數字的結果集。namespace test fo...