Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

パフォーマンスの良いGASの書き方 Best Practice

12,839 views

Published on

Atmosphere Tokyo 2014 Sandbox Session.
gcp ja night × TokyoGAS Day2 GAS Session.

Published in: Technology
  • Be the first to comment

パフォーマンスの良いGASの書き方 Best Practice

  1. 1. しょっちゅう 「XXXってサイトにある、 このサンプルコードを コピーして使ってるのだけど、 うちの会社のデータ件数だと タイムアウトしちゃうんです。 どうにか助けて下さい」 って言われて、毎回同じ内容で返答していて、 流石に疲れてきたので ちゃんとパフォーマンスの話をするからお前ら聞 いてろ下さい
  2. 2. 何やってる?
  3. 3. @soundTricker318 http://goo.gl/ZpUOs
  4. 4. http://www.bfts.co.jp
  5. 5. Contents うそ… 私のスクリプト 遅すぎ? パフォーマンス の良い書き方 まとめ Start End
  6. 6. う そ ・ ・ ・ 私 の ス ク リ プ ト 遅 す ぎ ・ ・ ・ ? http://www.pakutaso.com/
  7. 7. 公式ドキュメントにも 有りますが…
  8. 8. • GASは書き方によって非常にパフォーマンスが変 わります。 うそ…私の…
  9. 9. 質問
  10. 10. GASを使ったことがある人? 質問
  11. 11. GASでサンプルコードを コピーして 使ったことがある人? 質問
  12. 12. GASでサンプルコードを コピーして 社内のシステムとして 使っている人? 質問
  13. 13. GASでサンプルコードを コピーして 社内のシステムとして 使ってタイムアウトした人? 質問
  14. 14. • 巷のサンプルコードは比較的パフォーマンスが 悪いコードを書いている – 公式ドキュメントに書いてある書き方を守ってな いことが多い • https://developers.google.com/apps- script/best_practices?hl=ja – 多分読みやすくするためにそうしているのだと思い ます。 サンプルコード…
  15. 15. • パフォーマンスが悪いコードを使うと… –処理が終わらなくてタイムアウトする –なんかGASで作るの嫌になる –GAS遅い…と言いふらすようになる –困る サンプルコード
  16. 16. パ フ ォ ー マ ン ス の 良 いス ク リ プ ト で い い 感 じ に http://www.pakutaso.com/
  17. 17. パフォーマンスの良い スクリプトの書き方
  18. 18. • Spreadsheetに色つける処理 –データは100×100セル –セルに「hoge」と書いてあったら黄色に –ないなら無職 今回の処理
  19. 19. 以下のコードをSpreadsheet上のGASで実行すれば作れます。 今回の処理 var arr = ["hoge", "fuga", "foo", "bar" , "bus", "あいうえお", "かきくけこ"]; function make() { var grid = []; var header = []; for (var c = 0; c < 100; c++) { header.push(c + 1); } grid.push(header); for (var r = 1; r < 101; r++) { var row = []; for (var c = 0; c < 100; c++) { row.push(arr[Math.floor(Math.random() * arr.length)]); } grid.push(row); } SpreadsheetApp.getActiveSheet().getRange(1, 1, 101, 100).clear().setValues(grid); }
  20. 20. function badCode() { var spreadsheet = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1kzi8pXTZZrABgTGbJFqS ZrCHMCRL-LEEqQK2n4yQO-o/edit#gid=0"); for(var row = 2; row <= 101; row++) { for(var col = 1; col <= 100; col++) { var value = spreadsheet.getSheetByName("シート1").getRange(row, col).getValue(); if (value == "hoge") { spreadsheet.getSheetByName("シート1").getRange(row, col).setBackground("yellow"); } } } } 悪いコード
  21. 21. function goodCode() { var spreadsheet = SpreadsheetApp.openById("1kzi8pXTZZrABgTGbJFqSZrCHMCRL-LEEqQK2n4yQO-o"); var backgrounds = []; var sheet = spreadsheet.getSheetByName("シート1"); var targetRange = sheet.getRange(2, 1, 100, 100); var values = targetRange.getValues(); for(var rowIndex = 0; rowIndex < values.length; rowIndex++) { var row = values[rowIndex]; var backgroundRow = []; for(var colIndex = 0; colIndex < row.length; colIndex++) { var value = row[colIndex]; if (value == "hoge") { backgroundRow.push("yellow"); } else { backgroundRow.push(""); } } backgrounds.push(backgroundRow); } targetRange.setBackgrounds(backgrounds); } 良いコード
  22. 22. ①悪い部分を知る
  23. 23. • 遅い理由を知らないとどこを直してよいかわか りません – 実行トランスクリプトを使ってどこに時間がかかっ ているか確認する ①悪い部分を知る
  24. 24. ①悪い部分を知る
  25. 25. ②無駄なAPIアクセス を減らす
  26. 26. • GASのService呼び出しは全てネットワーク経由で行 われるため、時間がかかります。 少しでも無駄な呼び出しはしないようにします。 ②減らす ネットワーク経由
  27. 27. function badCode() { var spreadsheet = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1kzi8pXTZZrABgTGbJFqS ZrCHMCRL-LEEqQK2n4yQO-o/edit#gid=0"); for(var row = 2; row <= 101; row++) { for(var col = 1; col <= 100; col++) { var value = spreadsheet.getSheetByName("シート1").getRange(row, col).getValue(); if (value == "hoge") { spreadsheet.getSheetByName("シート1").getRange(row, col).setBackground("yellow"); } } } } ②減らす
  28. 28. function badCode() { var spreadsheet = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1kzi8pXTZZrABgTGbJFqSZrCHMCRL- LEEqQK2n4yQO-o/edit#gid=0"); var sheet = spreadsheet.getSheetByName("シート1"); for(var row = 2; row <= 101; row++) { for(var col = 1; col <= 100; col++) { var range = sheet.getRange(row, col); var value = range.getValue(); if (value == "hoge") { range.setBackground("yellow"); } } } } ②減らす
  29. 29. ③なるべく1度にする
  30. 30. • ②同じ原理でより呼び出し回数を減らすために getValues,setBackgrounds等のBatch Operationを 利用します。 ③1度にする 通常のgetValue() getValue() 1セルで1回アクセス = 100×100回アクセス
  31. 31. • ②同じ原理でより呼び出し回数を減らすために getValues,setBackgrounds等のBatch Operationを 利用します。 ③1度にする getValues() getValues) 100×100セルを1回アクセス = 1回アクセス
  32. 32. function badCode() { var spreadsheet = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1kzi8pXTZZrABgTGbJFqSZrCHMCRL- LEEqQK2n4yQO-o/edit#gid=0"); var sheet = spreadsheet.getSheetByName("シート1"); for(var row = 2; row <= 101; row++) { for(var col = 1; col <= 100; col++) { var range = sheet.getRange(row, col); var value = range.getValue(); if (value == "hoge") { range.setBackground("yellow"); } } } } ③1度にする
  33. 33. function badCode() { var spreadsheet = SpreadsheetApp .openByUrl("https://docs.google.com/spreadsheets/d/1kzi8pXTZZrABgTGbJFqSZrCHMCRL-LEEqQK2n4yQO-o/edit#gid=0"); var backgrounds = []; var sheet = spreadsheet.getSheetByName("シート1"); var targetRange = sheet.getRange(2, 1, 100, 100); var values = targetRange.getValues(); for(var rowIndex = 0; rowIndex < values.length; rowIndex++) { var row = values[rowIndex]; var backgroundRow = []; for(var colIndex = 0; colIndex < row.length; colIndex++) { var value = range.getValue(); if (value == "hoge") { backgrounds.push("yellow"); } else { backgrounds.push(“"); } } backgrounds.push(backgroundRow); } targetRange.setBackgrounds(backgrounds); } ③1度にする
  34. 34. • 大体のスクリプトはこの②、③を実施すればかなりパ フォーマンスが良くなります。
  35. 35. ④ 我に返る
  36. 36. • 今回の処理はGASでやる必要がありません。 Sheetsの標準機能でやれることはそっちでやりましょ う – 今回のはセルの条件付き書式でできます。 – 新しいSpreadsheetはかなり細かい書式が使えるので 確認して下さい。 ④我に返る
  37. 37. openByIdとopenByUrl
  38. 38. • Spreadsheet,Forms自体などを取得する際に利用す るopenByIdとopenByUrlというメソッドが有ります。 • これらは比較的openByIdの方が速い – IDはURL中のなんかよくわかない文字の部分がだいたいそれ openByIdとUrl https://docs.google.com/spreadsheets/d/1kzi8pXTZZrABgTGbJFqSZrCHMCRL-LEEqQK2n4yQO- o/edit#gid=0
  39. 39. UiApp
  40. 40. • UiAppを利用するときはなるべくClientHandler等ク ライアントサイドで動くイベントハンドラを活用する – UiAppのイベントハンドラは上記以外は全てサーバコールに なりおっそい – 適切にClientHandlerを利用するとかなりUXがよくなる UiApp
  41. 41. HtmlService
  42. 42. • HtmlServiceのパフォーマンスを良くする書き方の話も公式 ページに乗っている HtmlService
  43. 43. • 基本的には – データの取得は非同期に行う • doGet内などHtmlService呼び出し前に行わない – <html>,<head>,<body>タグなどは利用しない • cajaにより自動的に<caja-v-html>に変えられるので意味が無い • 変えられる分時間がかかるので使わない – Javascriptは最後に読み込む • <script>タグはファイルの一番末尾に書いておく • そのほうが画面が表示されてからクライアントサイドのJavascriptが実行される HtmlService
  44. 44. • 大橋の感覚として – 外部のJSやCSSは使わない方が良い • 使う場合は<script src=“xxx”>とはせず、<script>ここにコピペ</script>して、埋 め込んでしまう。 • cajaはGoogle経由で外部JS、CSSを取得するので遅い – 画面遷移はJavascriptを使って一部分だけ切り替える • doGetを毎回すると遅い • SPA(Single Page Application)の様にJSで画面を切り替えたほうが速い • というより画面切り替えはしないほうが良い HtmlService
  45. 45. どうしても遅い
  46. 46. • どうしても遅い時は… – UrlFetchAppを利用してGoogle APIを直接呼び出す。 – 直接呼び出すと、欲しいデータが1回の操作で取得できる場 合がある • CalendarAppやDriveAppなどでよくある • fieldsパラメータを利用すると不要なデータを取得しない ためネットワーク的にも良い どうしても遅い
  47. 47. • どうしても遅い時は… – 本当にリアルタイム(わざわざ人が待って)でやる必 要があるか考える • Triggerを利用して遅延実行 & 通知でも良いのではない か? • 朝一回実行すれば大丈夫なんじゃないか? • 実行タイミングは定期的でも良いのじゃないか? どうしても遅い
  48. 48. • どうしても遅い時は… – ちゃんとGASで作って良いのか考える – 金で解決できるのならGAEやGCPを使ったほうが良 い – SpreadsheetをDBとして使っている場合もそう • 大量のデータなら場合によってはFusion Table もっと多いならBigQueryを検討 どうしても遅い
  49. 49. まとめ
  50. 50. GASで 困ったら
  51. 51. #gasja
  52. 52. Google Apps API Japan http://goo.gl/FcU0C
  53. 53. @soundTricker318 http://goo.gl/ZpUOs
  54. 54. 会社: http://goo.gl/CfVPf 個人: http://goo.gl/kVTv3

×