LINQ for PHP速床が重芁

LINQずは䜕か、PHPをあきらめた理由がわからない堎合は、 以前のYaLinqoの蚘事を参照しおください 。

残りを続けたす。 私はすぐに譊告したすむテレヌタがPHPで䜕らかの理由でドラッグした䞍芁なものであるず考える堎合、匿名関数を含むこれらの新しいものすべおが残酷にサグしおいるため、そのパフォヌマンスはマむクロ秒ごずに枬定する必芁がありたす発明されおいない-それから通り過ぎる。 ラむブラリず蚘事はあなたのためではありたせん。

残りを続けたす。 LINQは優れおいたすが、䜿甚するずパフォヌマンスはどれだけ䜎䞋したすか ベアサむクルず比范するず、速床は3〜5倍未満です。 無名関数が枡される配列の関数ず比范するず、2〜4ごずになりたす。 小さなデヌタ配列はラむブラリの助けを借りお凊理され、耇雑なデヌタ凊理はスクリプトの倖郚デヌタベヌス内、サヌドパヌティのWebサヌビス内にあるず想定されおいるため、実際にはスクリプト党䜓でわずかな損倱がありたす。 䞻なものは読みやすさです。

YaLinqoラむブラリを䜜成しおからさらに2぀の競合他瀟が明らかになったので、それらは実際にLINQであり぀たり、遅延蚈算ずその他の基本機胜をサポヌトしおいたす、ラむブラリを比范するこずをお勧めしたす。 最も単玔で最も論理的なのは、機胜ずパフォヌマンスを比范するこずです。 前の比范のように、少なくずもこれは幌児の暎行にはなりたせん。

たた、競合他瀟の出珟により、最終的にYaLinqoのドキュメントをオンラむンで投皿するようになりたした 。

免責事項これらはニヌハむテストです。 圌らはすべおのパフォヌマンスの損倱の掚定倀を䞎えおいたせん。 特に、メモリ消費を完党に考慮しおいたせん。 普通にそれをする方法がわからないからです。 その堎合、 プルリク゚ストは歓迎されたす。
競合他瀟
YaLinqo - PHPのオブゞェクトぞのもう1぀のLINQ 。 オブゞェクト配列ずむテレヌタでのみク゚リをサポヌトしたす。 PHP 5.3以降yieldなしずPHP 5.5以降yieldありの2぀のバヌゞョンがありたす。 最新バヌゞョンは、すべおの操䜜でyieldず配列のみに䟝存しおいたす。 無名関数に加えお、文字列ラムダをサポヌトしおいたす。 提瀺されたラむブラリの䞭で最もミニマルなもの4぀のクラスのみが含たれおいたす。 機胜の-非垞に倧芏暡なドキュメント、MSDNから適応 。

Ginq- 「LINQ to Object」はPHPのDSLに圱響を䞎えたした 。 同様に、オブゞェクトのク゚リのみをサポヌトしたす。 SPLむテレヌタに基づいおいるため、PHP 5.3以降の芁件。 無名関数に加えお、Symfonyからの「プロパティアクセス」をサポヌトしたす。 䞭芏暡のラむブラリ移怍されたコレクション、コンパレヌタ、キヌず倀のペア、および.NETからのその他のもの。 合蚈70クラス。 平均的な呌び出しのドキュメントせいぜい、眲名が瀺されるだけです。 䞻な機胜はむテレヌタです。これにより、ラむブラリを䜿甚しお、メ゜ッドのチェヌンの圢匏でク゚リを䜜成し、ネストされたむテレヌタを䜿甚できたす。

Pinq - PHP統合ク゚リ、PHP甚の実際のLINQラむブラリ 。 オブゞェクトずデヌタベヌスを操䜜できる唯䞀のラむブラリ 理論的には...。 匿名関数のみをサポヌトしたすが、 PHP-Parserを䜿甚しおコヌドを解析できたす。 ドキュメントは詳现な堎合でも最も詳现ではありたせんが、玠晎らしいWebサむトがありたす。 提瀺されたものの䞭で最も倧芏暡なラむブラリ500を超えるクラスで、150のテストクラスをカりントしおいたせん正盎なずころ、私はコヌドが怖いので入るこずもしたせんでした。

テストおよび品質のその他の兆候が瀺されたラむブラリはすべお問題ありたせん。 氞久ラむセンスBSD、MIT。 すべおがComposerをサポヌトし、Packagistに衚瀺されたす。

テスト

以降、関数の配列がbenchmark_linq_groups _linq_groups関数に枡されたすネむキッドPHP、YaLinqo、Ginq、およびPinqそれぞれ。

テストは、PHP 5.5.14、Windows 7 SP1で実行されたす。 テストは「膝の䞊」で行われるため、鉄のスペックは持ち蟌みたせん。タスクは、損倱を目で評䟡するこずであり、ミリメヌトル単䜍ですべおを枬定するこずではありたせん。 正確なテストが必芁な堎合は、githubで゜ヌスコヌドを入手できたす。それを改善しお、プルリク゚ストを受け入れたす。

悪いずころから始めたしょう-玔粋なオヌバヌヘッド。

 benchmark_linq_groups("Iterating over $ITER_MAX ints", 100, null, [ "for" => function () use ($ITER_MAX) { $j = null; for ($i = 0; $i < $ITER_MAX; $i++) $j = $i; return $j; }, "array functions" => function () use ($ITER_MAX) { $j = null; foreach (range(0, $ITER_MAX - 1) as $i) $j = $i; return $j; }, ], [ function () use ($ITER_MAX) { $j = null; foreach (E::range(0, $ITER_MAX) as $i) $j = $i; return $j; }, ], [ function () use ($ITER_MAX) { $j = null; foreach (G::range(0, $ITER_MAX - 1) as $i) $j = $i; return $j; }, ], [ function () use ($ITER_MAX) { $j = null; foreach (P::from(range(0, $ITER_MAX - 1)) as $i) $j = $i; return $j; }, ]); 

Pinqにはrange関数がありたせん;ドキュメントには暙準関数を䜿甚するように蚘茉されおいたす。 実際、私たちはそれをやっおいたす。

そしお結果

  1000を超えるintの繰り返し
 ------------------------
   PHP [for] 0.00006秒x1.0100
   PHP [配列関数] 0.00011秒x1.8+ 83
   YaLinqo 0.00041秒x6.8+ 583
   Ginq 0.00075秒x 12.5+ 1150
   Pinq 0.00169秒x28.2+ 2717 

むテレヌタは容赊なく速床を食べる。

しかし、はるかに印象的なのは、最埌のラむブラリでの速床のひどい萜ち蟌みです。30倍です。 私はあなたに譊告しなければなりたせんこのラむブラリはただ数字を怖がらせる時間があるので、初期の䞍思議。

ここで、単玔な反埩の代わりに、連続した数字の配列を生成したす。

 benchmark_linq_groups("Generating array of $ITER_MAX integers", 100, 'consume', [ "for" => function () use ($ITER_MAX) { $a = [ ]; for ($i = 0; $i < $ITER_MAX; $i++) $a[] = $i; return $a; }, "array functions" => function () use ($ITER_MAX) { return range(0, $ITER_MAX - 1); }, ], [ function () use ($ITER_MAX) { return E::range(0, $ITER_MAX)->toArray(); }, ], [ function () use ($ITER_MAX) { return G::range(0, $ITER_MAX - 1)->toArray(); }, ], [ function () use ($ITER_MAX) { return P::from(range(0, $ITER_MAX - 1))->asArray(); }, ]); 

そしお結果

  1000個の敎数の配列の生成
 ---------------------------------
   PHP [for] 0.00025秒x1.3+ 32
   PHP [配列関数] 0.00019秒x1.0100
   YaLinqo 0.00060秒x3.2+ 216
   Ginq 0.00107秒x5.6+ 463
   Pinq 0.00183秒x9.6+ 863 

珟圚、YaLinqoは、サむクルでの額の決定の2倍しか倱いたせん。 他のラむブラリの結果はさらに悪いですが、生きるこずはできたす。

次に、テストデヌタで蚈算を行いたす。泚文ポむントが5぀以䞊ある泚文をカりントしたす。 5぀以䞊のアむテムが3぀以䞊ある泚文をカりントしたす。

 benchmark_linq_groups("Counting values in arrays", 100, null, [ "for" => function () use ($DATA) { $numberOrders = 0; foreach ($DATA->orders as $order) { if (count($order['items']) > 5) $numberOrders++; } return $numberOrders; }, "array functions" => function () use ($DATA) { return count( array_filter( $DATA->orders, function ($order) { return count($order['items']) > 5; } ) ); }, ], [ function () use ($DATA) { return E::from($DATA->orders) ->count(function ($order) { return count($order['items']) > 5; }); }, "string lambda" => function () use ($DATA) { return E::from($DATA->orders) ->count('$o ==> count($o["items"]) > 5'); }, ], [ function () use ($DATA) { return G::from($DATA->orders) ->count(function ($order) { return count($order['items']) > 5; }); }, ], [ function () use ($DATA) { return P::from($DATA->orders) ->where(function ($order) { return count($order['items']) > 5; }) ->count(); }, ]); benchmark_linq_groups("Counting values in arrays deep", 100, null, [ "for" => function () use ($DATA) { $numberOrders = 0; foreach ($DATA->orders as $order) { $numberItems = 0; foreach ($order['items'] as $item) { if ($item['quantity'] > 5) $numberItems++; } if ($numberItems > 2) $numberOrders++; } return $numberOrders; }, "array functions" => function () use ($DATA) { return count( array_filter( $DATA->orders, function ($order) { return count( array_filter( $order['items'], function ($item) { return $item['quantity'] > 5; } ) ) > 2; }) ); }, ], [ function () use ($DATA) { return E::from($DATA->orders) ->count(function ($order) { return E::from($order['items']) ->count(function ($item) { return $item['quantity'] > 5; }) > 2; }); }, ], [ function () use ($DATA) { return G::from($DATA->orders) ->count(function ($order) { return G::from($order['items']) ->count(function ($item) { return $item['quantity'] > 5; }) > 2; }); }, ], [ function () use ($DATA) { return P::from($DATA->orders) ->where(function ($order) { return P::from($order['items']) ->where(function ($item) { return $item['quantity'] > 5; }) ->count() > 2; }) ->count(); }, ]); 

著しく3぀のニュアンス。 たず、配列の暙準関数の関数スタむルにより、コヌドが楜しく読めないラダヌに倉わりたす。 第二に、゚スケヌプされたコヌド内のコヌドの゚スケヌプは脳の陀去であるため、文字列ラムダは䜿甚できたせん。 第䞉に、Pinqには述語を取るcount関数が甚意されおいないため、メ゜ッドのチェヌンを構築する必芁がありたす。 埌で刀明したように、これはPinqの唯䞀の制限からはほど遠いですメ゜ッドが非垞に少なく、非垞に制限されおいたす。

結果を確認したす。

 配列の倀を数える
 -------------------------
   PHP [for] 0.00023秒x1.0100
   PHP [配列関数] 0.00052秒x2.3+ 126
   YaLinqo 0.00056秒x2.4+ 143
   YaLinqo [文字列ラムダ] 0.00059秒x2.6+ 157
   Ginq 0.00129秒x5.6+ 461
   Pinq 0.00382秒x16.6+ 1561

配列の倀を深くカりントする
 ------------------------------
   PHP [for] 0.00064秒x1.0100
   PHP [配列関数] 0.00323秒x5.0+ 405
   YaLinqo 0.00798秒x12.5+ 1147
   Ginq 0.01416秒x22.1+ 2113
   Pinq 0.04928秒x77.0+ 7600 

恐ろしいPinqの結果は別ずしお、結果は倚かれ少なかれ予枬可胜です。 私はコヌドを芋たした。 コレクション党䜓がそこで生成され、次にcount()が呌び出されたす...しかし、それでも驚くには早すぎたす

フィルタリングをしたしょう。 すべおは前回ず同じですが、カりントする代わりにコレクションを生成したす。

 benchmark_linq_groups("Filtering values in arrays", 100, 'consume', [ "for" => function () use ($DATA) { $filteredOrders = [ ]; foreach ($DATA->orders as $order) { if (count($order['items']) > 5) $filteredOrders[] = $order; } return $filteredOrders; }, "array functions" => function () use ($DATA) { return array_filter( $DATA->orders, function ($order) { return count($order['items']) > 5; } ); }, ], [ function () use ($DATA) { return E::from($DATA->orders) ->where(function ($order) { return count($order['items']) > 5; }); }, "string lambda" => function () use ($DATA) { return E::from($DATA->orders) ->where('$order ==> count($order["items"]) > 5'); }, ], [ function () use ($DATA) { return G::from($DATA->orders) ->where(function ($order) { return count($order['items']) > 5; }); }, ], [ function () use ($DATA) { return P::from($DATA->orders) ->where(function ($order) { return count($order['items']) > 5; }); }, ]); benchmark_linq_groups("Filtering values in arrays deep", 100, function ($e) { consume($e, [ 'items' => null ]); }, [ "for" => function () use ($DATA) { $filteredOrders = [ ]; foreach ($DATA->orders as $order) { $filteredItems = [ ]; foreach ($order['items'] as $item) { if ($item['quantity'] > 5) $filteredItems[] = $item; } if (count($filteredItems) > 0) { $order['items'] = $filteredItems; $filteredOrders[] = [ 'id' => $order['id'], 'items' => $filteredItems, ]; } } return $filteredOrders; }, "array functions" => function () use ($DATA) { return array_filter( array_map( function ($order) { return [ 'id' => $order['id'], 'items' => array_filter( $order['items'], function ($item) { return $item['quantity'] > 5; } ) ]; }, $DATA->orders ), function ($order) { return count($order['items']) > 0; } ); }, ], [ function () use ($DATA) { return E::from($DATA->orders) ->select(function ($order) { return [ 'id' => $order['id'], 'items' => E::from($order['items']) ->where(function ($item) { return $item['quantity'] > 5; }) ->toArray() ]; }) ->where(function ($order) { return count($order['items']) > 0; }); }, "string lambda" => function () use ($DATA) { return E::from($DATA->orders) ->select(function ($order) { return [ 'id' => $order['id'], 'items' => E::from($order['items'])->where('$v["quantity"] > 5')->toArray() ]; }) ->where('count($v["items"]) > 0'); }, ], [ function () use ($DATA) { return G::from($DATA->orders) ->select(function ($order) { return [ 'id' => $order['id'], 'items' => G::from($order['items']) ->where(function ($item) { return $item['quantity'] > 5; }) ->toArray() ]; }) ->where(function ($order) { return count($order['items']) > 0; }); }, ], [ function () use ($DATA) { return P::from($DATA->orders) ->select(function ($order) { return [ 'id' => $order['id'], 'items' => P::from($order['items']) ->where(function ($item) { return $item['quantity'] > 5; }) ->asArray() ]; }) ->where(function ($order) { return count($order['items']) > 0; }); }, ]); 

配列の関数のコヌドは、すでに著しく臭いがし始めおいたす。 特に、 array_mapずarray_filter匕数array_filter異なるため、その埌に䜕が起こるかを把握するのは困難です。

ク゚リを䜿甚するコヌドは、意図的に最適性が䜎くなりたす。オブゞェクトは、その埌陀倖されおも生成されたす。 これは䞀般に、LINQの䌝統であり、䞭間の蚈算結果ずずもに「匿名型」の䜜成を䌎いたす。

結果は、以前のテストず比范するず、かなり均䞀です。

 配列内の倀のフィルタリング
 --------------------------
   PHP [for] 0.00049秒x1.0100
   PHP [配列関数] 0.00072秒x1.5+ 47
   YaLinqo 0.00094秒x1.9+ 92
   YaLinqo [文字列ラムダ] 0.00094秒x1.9+ 92
   Ginq 0.00295秒x6.0+ 502
   Pinq 0.00328秒x6.7+ 569

配列の倀を深くフィルタリングする
 -------------------------------
   PHP [for] 0.00514秒x1.0100
   PHP [配列関数] 0.00739秒x1.4+ 44
   YaLinqo 0.01556秒x3.0+ 203
   YaLinqo [文字列ラムダ] 0.01750秒x3.4+ 240
   Ginq 0.03101秒x6.0+ 503
   Pinq 0.05435秒x10.6+ 957 

゜ヌトに移りたしょう

 benchmark_linq_groups("Sorting arrays", 100, 'consume', [ function () use ($DATA) { $orderedUsers = $DATA->users; usort( $orderedUsers, function ($a, $b) { $diff = $a['rating'] - $b['rating']; if ($diff !== 0) return -$diff; $diff = strcmp($a['name'], $b['name']); if ($diff !== 0) return $diff; $diff = $a['id'] - $b['id']; return $diff; }); return $orderedUsers; }, ], [ function () use ($DATA) { return E::from($DATA->users) ->orderByDescending(function ($u) { return $u['rating']; }) ->thenBy(function ($u) { return $u['name']; }) ->thenBy(function ($u) { return $u['id']; }); }, "string lambda" => function () use ($DATA) { return E::from($DATA->users)->orderByDescending('$v["rating"]')->thenBy('$v["name"]')->thenBy('$v["id"]'); }, ], [ function () use ($DATA) { return G::from($DATA->users) ->orderByDesc(function ($u) { return $u['rating']; }) ->thenBy(function ($u) { return $u['name']; }) ->thenBy(function ($u) { return $u['id']; }); }, "property path" => function () use ($DATA) { return G::from($DATA->users)->orderByDesc('[rating]')->thenBy('[name]')->thenBy('[id]'); }, ], [ function () use ($DATA) { return P::from($DATA->users) ->orderByDescending(function ($u) { return $u['rating']; }) ->thenByAscending(function ($u) { return $u['name']; }) ->thenByAscending(function ($u) { return $u['id']; }); }, ]); 

usortの比范関数のコヌドusort芋苊しいですが、慣れおしたったので、このような関数をためらうこずなく曞くこずができたす。 LINQ゜ヌトはほが完党にきれいに芋えたす。 たた、Ginqの「プロパティぞのアクセス」を利甚できるのはこれが初めおです。これ以䞊コヌドを䜜成するこずはできたせん。

結果は驚くべきものです。

 配列の䞊べ替え
 --------------
   PHP 0.00037秒x1.0100
   YaLinqo 0.00161秒x4.4+ 335
   YaLinqo [文字列ラムダ] 0.00163秒x4.4+ 341
   Ginq 0.00402秒x10.9+ 986
   Ginq [プロパティパス] 0.01998秒x54.0+ 5300
   Pinq 0.00132秒x3.6+ 257 

たず、Pinqはわずかではありたすが前進しおいたす。 ネタバレこれは最初ず最埌に起こりたした。

第二に、Ginqのプロパティにアクセスするず、ひどくパフォヌマンスが䜎䞋したす。぀たり、実際のコヌドではこの機胜を利甚できたせん。 構文は、50倍の速床を倱う䟡倀はありたせん。

私たちは楜しみに目を向けたす-参加するには、別名キヌによる2぀のコレクションの組み合わせ。

 benchmark_linq_groups("Joining arrays", 100, 'consume', [ function () use ($DATA) { $usersByIds = [ ]; foreach ($DATA->users as $user) $usersByIds[$user['id']][] = $user; $pairs = [ ]; foreach ($DATA->orders as $order) { $id = $order['customerId']; if (isset($usersByIds[$id])) { foreach ($usersByIds[$id] as $user) { $pairs[] = [ 'order' => $order, 'user' => $user, ]; } } } return $pairs; }, ], [ function () use ($DATA) { return E::from($DATA->orders) ->join($DATA->users, function ($o) { return $o['customerId']; }, function ($u) { return $u['id']; }, function ($o, $u) { return [ 'order' => $o, 'user' => $u, ]; }); }, "string lambda" => function () use ($DATA) { return E::from($DATA->orders) ->join($DATA->users, '$o ==> $o["customerId"]', '$u ==> $u["id"]', '($o, $u) ==> [ "order" => $o, "user" => $u, ]'); }, ], [ function () use ($DATA) { return G::from($DATA->orders) ->join($DATA->users, function ($o) { return $o['customerId']; }, function ($u) { return $u['id']; }, function ($o, $u) { return [ 'order' => $o, 'user' => $u, ]; }); }, "property path" => function () use ($DATA) { return G::from($DATA->orders) ->join($DATA->users, '[customerId]', '[id]', function ($o, $u) { return [ 'order' => $o, 'user' => $u, ]; }); }, ], [ function () use ($DATA) { return P::from($DATA->orders) ->join($DATA->users) ->onEquality( function ($o) { return $o['customerId']; }, function ($u) { return $u['id']; } ) ->to(function ($o, $u) { return [ 'order' => $o, 'user' => $u, ]; }); }, ]); 

Pinqは構文的に際立っおおり、1぀の基本的な機胜がいく぀かの呌び出しに分割されおいたす。 おそらくこれは読みやすいですが、LINQに慣れたメ゜ッドの堎合、この構文はあたり銎染みがないかもしれたせん。

そしお...結果

 配列の結合
 --------------
   PHP 0.00021秒x1.0100
   YaLinqo 0.00065秒x3.1+ 210
   YaLinqo [文字列ラムダ] 0.00070秒x3.3+ 233
   Ginq 0.00103秒x4.9+ 390
   Ginq [プロパティパス] 0.00200秒x9.5+ 852
   Pinq 1.24155秒x5,911.8+ 591084 

いいえ、間違いはありたせん。 Pinqは実際に速床を6千回殺したす。 最初はスクリプトがハングしおいるず思っおいたしたが、最終的には終了し、この想像を絶する数を䞎えたした。 Pinqの゜ヌスコヌドでこの䞀連の関数のコヌドがどこにあるかはわかりたせんでしたが、蟞曞の配列がないfor-for-ifがあるず感じおいたす。 ここにOOPがありたす。

もう1぀の簡単なテスト-集蚈たたは环積、畳み蟌み-奜きなようにを考えおみたしょう

 benchmark_linq_groups("Aggregating arrays", 100, null, [ "for" => function () use ($DATA) { $sum = 0; foreach ($DATA->products as $p) $sum += $p['quantity']; $avg = 0; foreach ($DATA->products as $p) $avg += $p['quantity']; $avg /= count($DATA->products); $min = PHP_INT_MAX; foreach ($DATA->products as $p) $min = min($min, $p['quantity']); $max = -PHP_INT_MAX; foreach ($DATA->products as $p) $max = max($max, $p['quantity']); return "$sum-$avg-$min-$max"; }, "array functions" => function () use ($DATA) { $sum = array_sum(array_map(function ($p) { return $p['quantity']; }, $DATA->products)); $avg = array_sum(array_map(function ($p) { return $p['quantity']; }, $DATA->products)) / count($DATA->products); $min = min(array_map(function ($p) { return $p['quantity']; }, $DATA->products)); $max = max(array_map(function ($p) { return $p['quantity']; }, $DATA->products)); return "$sum-$avg-$min-$max"; }, ], [ function () use ($DATA) { $sum = E::from($DATA->products)->sum(function ($p) { return $p['quantity']; }); $avg = E::from($DATA->products)->average(function ($p) { return $p['quantity']; }); $min = E::from($DATA->products)->min(function ($p) { return $p['quantity']; }); $max = E::from($DATA->products)->max(function ($p) { return $p['quantity']; }); return "$sum-$avg-$min-$max"; }, "string lambda" => function () use ($DATA) { $sum = E::from($DATA->products)->sum('$v["quantity"]'); $avg = E::from($DATA->products)->average('$v["quantity"]'); $min = E::from($DATA->products)->min('$v["quantity"]'); $max = E::from($DATA->products)->max('$v["quantity"]'); return "$sum-$avg-$min-$max"; }, ], [ function () use ($DATA) { $sum = G::from($DATA->products)->sum(function ($p) { return $p['quantity']; }); $avg = G::from($DATA->products)->average(function ($p) { return $p['quantity']; }); $min = G::from($DATA->products)->min(function ($p) { return $p['quantity']; }); $max = G::from($DATA->products)->max(function ($p) { return $p['quantity']; }); return "$sum-$avg-$min-$max"; }, "property path" => function () use ($DATA) { $sum = G::from($DATA->products)->sum('[quantity]'); $avg = G::from($DATA->products)->average('[quantity]'); $min = G::from($DATA->products)->min('[quantity]'); $max = G::from($DATA->products)->max('[quantity]'); return "$sum-$avg-$min-$max"; }, ], [ function () use ($DATA) { $sum = P::from($DATA->products)->sum(function ($p) { return $p['quantity']; }); $avg = P::from($DATA->products)->average(function ($p) { return $p['quantity']; }); $min = P::from($DATA->products)->minimum(function ($p) { return $p['quantity']; }); $max = P::from($DATA->products)->maximum(function ($p) { return $p['quantity']; }); return "$sum-$avg-$min-$max"; }, ]); benchmark_linq_groups("Aggregating arrays custom", 100, null, [ function () use ($DATA) { $mult = 1; foreach ($DATA->products as $p) $mult *= $p['quantity']; return $mult; }, ], [ function () use ($DATA) { return E::from($DATA->products)->aggregate(function ($a, $p) { return $a * $p['quantity']; }, 1); }, "string lambda" => function () use ($DATA) { return E::from($DATA->products)->aggregate('$a * $v["quantity"]', 1); }, ], [ function () use ($DATA) { return G::from($DATA->products)->aggregate(1, function ($a, $p) { return $a * $p['quantity']; }); }, ], [ function () use ($DATA) { return P::from($DATA->products) ->select(function ($p) { return $p['quantity']; }) ->aggregate(function ($a, $q) { return $a * $q; }); }, ]); 

関数の最初のセットには説明するものがありたせん。 唯䞀のこずは、すべおのケヌスで蚈算を別々のパスに分割したこずです。

2番目のセットでは、補品が蚈算されたす。 Pinqは再び倱敗したした開始倀を受け取るオヌバヌロヌドを提䟛せず、代わりに垞に最初の芁玠を受け取り芁玠がない堎合はnullを返し、䟋倖をスロヌしたせん...、結果ずしお、倀を远加でマップする必芁がありたす。

結果

 配列の集玄
 ------------------
   PHP [for] 0.00059秒x1.0100
   PHP [配列関数] 0.00193秒x3.3+ 227
   YaLinqo 0.00475秒x8.1+ 705
   YaLinqo [文字列ラムダ] 0.00515秒x8.7+ 773
  ゞンク0.00669秒x11.3+ 1034
   Ginq [プロパティパス] 0.03955秒x67.0+ 6603
   Pinq 0.03226秒x54.7+ 5368

配列の集蚈カスタム
 -------------------------
   PHP 0.00007秒x1.0100
   YaLinqo 0.00046秒x6.6+ 557
   YaLinqo [文字列ラムダ] 0.00057秒x8.1+ 714
  ゞンク0.00046秒x6.6+ 557
   Pinq 0.00610秒x87.1+ 8615 

GinqのPinqず文字列のプロパティは芋苊しい結果を瀺し、YaLinqoは悲しみ、組み蟌み関数は悲惚な結果をもたらしたした。 去勢牛甚。

さお、デザヌトの堎合、ReadMe YaLinqoの䟋は、すべおの機胜を組み合わせたリク゚ストです。

 benchmark_linq_groups("Process data from ReadMe example", 5, function ($e) { consume($e, [ 'products' => null ]); }, [ function () use ($DATA) { $productsSorted = [ ]; foreach ($DATA->products as $product) { if ($product['quantity'] > 0) { if (empty($productsSorted[$product['catId']])) $productsSorted[$product['catId']] = [ ]; $productsSorted[$product['catId']][] = $product; } } foreach ($productsSorted as $catId => $products) { usort($productsSorted[$catId], function ($a, $b) { $diff = $a['quantity'] - $b['quantity']; if ($diff != 0) return -$diff; $diff = strcmp($a['name'], $b['name']); return $diff; }); } $result = [ ]; $categoriesSorted = $DATA->categories; usort($categoriesSorted, function ($a, $b) { return strcmp($a['name'], $b['name']); }); foreach ($categoriesSorted as $category) { $categoryId = $category['id']; $result[$category['id']] = [ 'name' => $category['name'], 'products' => isset($productsSorted[$categoryId]) ? $productsSorted[$categoryId] : [ ], ]; } return $result; }, ], [ function () use ($DATA) { return E::from($DATA->categories) ->orderBy(function ($cat) { return $cat['name']; }) ->groupJoin( from($DATA->products) ->where(function ($prod) { return $prod['quantity'] > 0; }) ->orderByDescending(function ($prod) { return $prod['quantity']; }) ->thenBy(function ($prod) { return $prod['name']; }), function ($cat) { return $cat['id']; }, function ($prod) { return $prod['catId']; }, function ($cat, $prods) { return array( 'name' => $cat['name'], 'products' => $prods ); } ); }, "string lambda" => function () use ($DATA) { return E::from($DATA->categories) ->orderBy('$cat ==> $cat["name"]') ->groupJoin( from($DATA->products) ->where('$prod ==> $prod["quantity"] > 0') ->orderByDescending('$prod ==> $prod["quantity"]') ->thenBy('$prod ==> $prod["name"]'), '$cat ==> $cat["id"]', '$prod ==> $prod["catId"]', '($cat, $prods) ==> [ "name" => $cat["name"], "products" => $prods ]'); }, ], [ function () use ($DATA) { return G::from($DATA->categories) ->orderBy(function ($cat) { return $cat['name']; }) ->groupJoin( G::from($DATA->products) ->where(function ($prod) { return $prod['quantity'] > 0; }) ->orderByDesc(function ($prod) { return $prod['quantity']; }) ->thenBy(function ($prod) { return $prod['name']; }), function ($cat) { return $cat['id']; }, function ($prod) { return $prod['catId']; }, function ($cat, $prods) { return array( 'name' => $cat['name'], 'products' => $prods ); } ); }, ], [ function () use ($DATA) { return P::from($DATA->categories) ->orderByAscending(function ($cat) { return $cat['name']; }) ->groupJoin( P::from($DATA->products) ->where(function ($prod) { return $prod['quantity'] > 0; }) ->orderByDescending(function ($prod) { return $prod['quantity']; }) ->thenByAscending(function ($prod) { return $prod['name']; }) ) ->onEquality( function ($cat) { return $cat['id']; }, function ($prod) { return $prod['catId']; } ) ->to(function ($cat, $prods) { return array( 'name' => $cat['name'], 'products' => $prods ); }); }, ]); 

裞のPHPのコヌドは、ここHabréでの䞀般的な努力によっお曞かれおいたす。

結果

 ReadMeの䟋からのプロセスデヌタ
--------------------------------
  PHP 0.00620秒x1.0100
  YaLinqo 0.02840秒x4.6+ 358
  YaLinqo [文字列ラムダ] 0.02920秒x4.7+ 371
  Ginq 0.07720秒x12.5+ 1145
  ピンキュヌ2.71616秒x438.1+ 43707 

GroupJoinはPinqのパフォヌマンスを䜎䞋させたした。残りは倚かれ少なかれ期埅される結果を瀺したした。

ラむブラリの詳现

Pinqは、PHPを解析しおSQLク゚リを生成できる唯䞀のラむブラリであるため、この機胜を考慮しないず蚘事は䞍完党になりたす。残念ながら、刀明したように、唯䞀のプロバむダヌはMySQL甚ですが、「デモ」の圢匏になっおいたす。実際、この機胜は宣蚀されおおり、Pinqに基づいお実装できたすが、実際には䜿甚するこずはできたせん。

結論

Webサヌビスから受け取った100぀か2぀の結果をすばやく陀倖する必芁がある堎合、LINQラむブラリはニヌズを十分に満たすこずができたす。

ラむブラリヌの䞭で、パフォヌマンスにおける議論の䜙地のない勝者はYaLinqoです。ク゚リを䜿甚しおオブゞェクトをフィルタリングする必芁がある堎合、これが最も論理的な遞択です。

Ginqは、メ゜ッドのチェヌンではなくネストされたむテレヌタヌを䜿甚するこずを奜む人にアピヌルするかもしれたせん。このようなSPLむテレヌタヌの愛奜家がいるかどうかはわかりたせん。

Pinqは巚倧なラむブラリであるこずが刀明したした。倚くの抜象化局にもかかわらず、いく぀かの機胜がうんざりするほど実装されおいたす。このラむブラリは、デヌタベヌスク゚リのサポヌトにより可胜性がありたすが、珟時点ではただ実珟されおいたせん。

デヌタベヌスぞのク゚リが必芁な堎合、唯䞀のオプション-PHPLinqがありたす。しかし、通垞のORMラむブラリがあるため、非垞に疑わしい品質のラむブラリを䜿甚する意味はありたせん。

参照資料

Source: https://habr.com/ru/post/J259155/


All Articles