今回の記事はザマリンに関する記事ではなく、同期から寄せられた「遅延評価って何?」についての記事です。私自身も分かっていたようで実は全然分かってなかったな、ということが分かったので非常に勉強になる単元ですね。一応対象者としてはLINQをこれから勉強する初心者でも分かるように書いています!ただ、あくまでも主眼は遅延評価についてです。

会社での会話

同期同期

新人研修でLINQの講義やるんだけど、どういう所を喋ればいいかな

かりまたかりまた

遅延評価のとことか

同期同期

ごめん、正直、遅延評価の事分かってない…。遅延評価ってなにが良いの…?

かりまたかりまた

俺もふんわり分かってるつもりだけど上手く説明できないな。せや!記事に纏めよう!

そもそもLINQってなにさ?

りんちゃんりんちゃん

LINQとはLanguage Integrated Query の略称で、配列・データテーブル・XMLなどのデータ操作に用いられるのにゃ~。

データ操作って、具体的に何ができるの?

りんちゃんりんちゃん

LINQではデータ操作が出来ると書いたが、実際に何が出来るのかを簡単に書いてみるのにゃ~。

Q.1から100までを足した値を出力せよ

りんちゃんりんちゃん

「1から100まで足した値を出力せよ」という問題があった場合、以下の様にかけるのにゃ~。

for文で書くとこうなる

LINQを使うとこうなる

LINQを使って書いてどう変わった?
りんちゃんりんちゃん

乱暴な言い方をしてしまえば、LINQを使う事でfor文をある程度消すことが出来るようになるのにゃ~。

なんだとさんなんだとさん

なん…だと…

かりまたかりまた

for文を消すことが出来れば、ネスト(入れ子)が減ってコード全体の見通しが良くなります。そうするとコードの保守性も当然上がってきますね。

Q.「t」が含まれている苗字を出力せよ

りんちゃんりんちゃん

LINQが文字列操作にも強いことを示す為にもう一つ例を挙げてみるのにゃ~。「t」が含まれている苗字を出力するのにゃ~。

for文で書くとこうなる

LINQを使うとこうなる

LINQを使って書いてどう変わった?
りんちゃんりんちゃん

for文の中だけで完結させようとした場合、どうしてもif文を書いてやる必要が出てくるのにゃ~。

りんちゃんりんちゃん

LINQを使うことによって、予め「t」を含んだ苗字のみを抽出したコレクションに対してのみのループになるのにゃ~。

遅延評価とは何か?

かりまたかりまた

さて、LINQがどういうものかがざっくり分かった所で、本題の遅延評価について話を進めていきます。

意外と知らず知らずのうちに使っている遅延評価

りんちゃんりんちゃん

またまた問題なのにゃ~。

Q.以下の1から3までに対してReturnメソッドを実行させるプログラムの実行時間は何秒か?


りんちゃんりんちゃん

正解は 「約6秒」 なのにゃ~。

Q.以下の1から3までに対してReturnメソッドを実行させるプログラムの実行時間は何秒か?

りんちゃんりんちゃん

正解は 「約3秒」 なのにゃ~。

上のプログラムと下のプログラムは何が違うのか?

かりまたかりまた

異なる点は一つのみ。ToListメソッドでリスト化しているかどうかです。

何故、リスト化すると3秒で、リスト化しないと6秒なのか?

りんちゃんりんちゃん

まさしく、この答えが「遅延評価」そのものなのにゃ~。

りんちゃんりんちゃん

一つ目のforeach文にブレークポイントを置いて実行してみると違いが見て取れるのにゃ~。ToListメソッドでリスト化している方のプログラムは約3秒でブレークポイントに到達するのにゃ~。つまり、即時的に式が評価されているのにゃ~。

りんちゃんりんちゃん

では、リスト化しなかった方のプログラムはと言うと、1秒も経たずにブレークポイントに到達してるのにゃ~。foreach文で使用されるタイミングになって初めて評価されてるのにゃ~。なので文字通りの「遅延評価」という訳なのにゃ~。

かりまたかりまた

では何故、約6秒掛かってしまったのかと言うと、 集中評価するメソッドもしくはforeach文で使用される度に実行しなおしている からです。(つまり、キャッシュが効かない)

かりまたかりまた

このプログラムではforeach文が2回書かれてあり、リスト化をしていない状態であれば2度、squaresが評価されてしまうという訳ですね。

集中評価についての補足
りんちゃんりんちゃん

「遅延評価」に対しての対義的な意味合いを持つ「集中評価」に関して補足するのにゃ~。ToListメソッドToArrayメソッドSumメソッドなどは集中評価、つまりは即時的に評価されるメソッドなのにゃ~。

かりまたかりまた

ToListメソッドなんかはListクラスのインスタンスを生成しているのでメモリ上に値を持つ必要があります。メモリ上に値を持っちゃう事になるので勿論、集中評価な訳です。

遅延評価のメリット・デメリットについて

りんちゃんりんちゃん

遅延評価にはメリットとデメリットがあるのにゃ~。正しく把握することが良いプログラムへの一歩だにゃ~。まずは結論から。

遅延評価のメリット

  • 省メモリ
  • 無限ループにも対応可能
  • 返ってきた値を逐次反映させる事ができる

遅延評価のデメリット

  • よく分からずに使っているとパフォーマンスを落としてしまう

遅延評価のメリットについて深堀り

1点目:省メモリ

りんちゃんりんちゃん

遅延評価は省メモリだ!とよく言われているのにゃ~。実際の所どうなんだろう?と測ってみたところ数Kb程度の誤差だったのにゃ~。測り方が不味かったのかもしれにゃいが、コンパイラが最適化を掛けてくれたのだと今の所は思ってるのにゃ~。

2点目:無限ループにも対応可能

3点目:返ってきた値を逐次反映させる事が可能

りんちゃんりんちゃん

2点目、3点目は一纏めにして紹介するにゃ~。以下のプログラムは0から1ずつ無限ループ内で増加させたコレクションを10未満の間、出力するというプログラムだにゃ~。一見、正しく動作しなさそうだが、意図した通りに0~9までを1秒置きに出力して実行が完了するのにゃ~。

りんちゃんりんちゃん

まぁ、無限ループを噛ませても正しく実行するのはTakeWhileメソッドが処理を打ち切ってくれるからなんだにゃ~。

かりまたかりまた

無限ループでなくても、何かしら重い処理が全て終わってから表示!ではなく、処理が終了したものから表示!になればユーザ側からすると非常にストレスを感じにくくなると思います。

かりまたかりまた

例えば、Webページの情報が全て取得できてから表示される!ではなく、取得できた情報から表示される!の方が使っていて安心感がありませんか?

遅延評価のデメリットについて深堀り

よく分からずに使っているとパフォーマンスを落としてしまう

りんちゃんりんちゃん

遅延評価される式を何度も集中評価やforeach文などで使ってしまうと、都度都度で無駄に式が評価されてしまうよという事を上の方で書いたのにゃ~。もう少し詳しく知りたい方は以下のサイトを参考にすると良いのにゃ~。

まとめ

  • 遅延評価は文字通りに評価を遅延させているだけ
  • 使い方を誤るとパフォーマンスを落としますし銀の弾丸じゃないよ
  • でも正しく使えばユーザビリティを上げられる可能性を秘めているし省メモリ(なはず)