LoginSignup
6
6

More than 3 years have passed since last update.

memoiseによる1行変更するだけのShinyApp高速化

Last updated at Posted at 2019-08-31

Shiny App を高速化したいときに比較的簡単に試せるのがmemoiseを使ったデータのキャッシュ化です。それについて紹介します

memoise とは?

私がこのパッケージを初めて知ったのは、Shiny高速化を調べてる際にpromisesのドキュメントを読んでたときでした

image.png

参考 : Case study: converting a Shiny app to async

memoiseがどう役立つかというと、ある関数を同じインプットで何度も呼び出すなら、はじめて呼び出したときにデータをキャッシュ化して、2度目以降の呼び出しはそのキャッシュ化されたデータを返してあげよう というところです

キャッシュ先としては、なんらかのファイルシステム(例えば、 tmpfs) やクラウドストレージ(例えば、S3)を使うことができます

2019-10-21追記 また、キャッシュ先としてRedisを使うことも、次のPR通りにreduxパッケージを使ってやれば実装することができそうです : https://github.com/r-lib/memoise/pull/67

とくにmemoiseと相性が良いのが、Shiny Serverの上で、あるShiny Appを複数人が使用している場合です。よくあるパターンで、別のデータベースで毎日夜にデータが更新され、Shiny Appの閲覧時に独自関数を使ってそのデータをロードする処理が発生することを考えます

最初にそのShiny Appにアクセスしたときは、そのデータベースからデータをロードしますが、その処理をmemoiseでかぶせておけば、データがキャッシュ化されます。その結果、2度目以降にアクセスした人は、そのキャッシュ先からデータをロードすることができるので、高速に呼び出すことができます

では試してみましょう

公式ドキュメント

やるべきたった1つのこと

キャッシュ化したい関数にmemoiseをかぶせる だけです。まず適当にデータを読み込む関数を用意してみます

library(memoise)
set.seed(42)

load_data <- function(start_date, end_date){

  # Preprocess - ここにホントはデータベースへの接続やデータのクレンジング入っている
  Sys.sleep(5)

  # return data
  data <- rnorm(end_date - start_date, mean = 0, sd = 1)
  data
}

これのパフォーマンスをチェックしておくと、Sys.sleppをしたとおりデータのロードに5秒かかりました

> t <- proc.time()
> data <- load_data(as.Date("2019-08-01"), as.Date("2019-08-31"))
> (proc.time() - t)["elapsed"]
elapsed 
  5.008

これをmemoiseでかぶせてみます。キャッシュさせる先のファイルシステムは今回はホームディレクトリで適当に切っておきます

m_load_data <- memoise(load_data, cache = cache_filesystem("~/tmp"))

まず一回目の実行をしてみます。とくに実行時間は変わらないですね

(キャッシュ先にデータを書き出すということは、ストレージIOがボトルネックになることがあるので、適切な場所を選ばないと、遅くなる可能性はあります)

> t <- proc.time()
> data <- m_load_data(as.Date("2019-08-01"), as.Date("2019-08-31"))
> (proc.time() - t)["elapsed"]
elapsed 
  5.019 

しかし、2回目を実行してみると、ちゃんと爆速になりました(完)

> t <- proc.time()
> data <- m_load_data(as.Date("2019-08-01"), as.Date("2019-08-31"))
> (proc.time() - t)["elapsed"]
elapsed 
    0.148 

補足

のコードを読めばどうやって実現してるかの雰囲気はわかります。memoise用のnew.envを作ってその中でハッシュデータをもたせて覚えてる?みたいですね。ファイルシステムへの書き出しはRDSフォーマットのようです

実際自分が運用して複数人に提供しているShiny Appだと、別のホストのデータベースから複数の集計済みデータを日付指定でロードする必要があり、memoiseを使うことでかなり改善されました。一度試してみるのをおすすめします

(さらにいうと、1回目のアクセスを自動的に別のプロセスで定期的にアクセスさせる処理を書いておけば、より良いと思います)

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6