質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

2回答

1983閲覧

GAS スプレッドシートへの書き込みを並列処理で行うときに書き込まれる行を干渉しないようにしたい

dedede914

総合スコア63

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

2クリップ

投稿2023/08/26 05:48

実現したいこと

GASでデプロイしたwebアプリから並列処理で同時に一つのスプレッドシートへ書き込みをしたいです。(GASの6分制限を超えるため)
sheet.appendRow(list);
で書き込みを行っていますが、どうやら同じ行に何回か上書きされてしまうようで、ちゃんとすべてのデータを書き出すことができません。どうすればいいでしょうか

https://web-breeze.net/gas-running-over-time-limit/#toc3
このサイトを参考にしました。

発生している問題・エラーメッセージ

書き込まれる行がかぶってしまいデータが上書きされてしまう

該当のソースコード

javascript

1function doGet() { 2 return HtmlService.createHtmlOutputFromFile('webapp'); 3} 4 5function myFunction(n) { 6 let lists=[]; 7 //なんらかの処理 8 //例えば 9 list.push([1000+n,2000+n,3000+n]); 10 list.push([4000+n,5000+n,6000+n]); 11 list.push([7000+n,8000+n,9000+n]); 12 writedown(lists); 13} 14 15function writedown(list) { 16 let sp=SpreadsheetApp.openById("~~~~~~~~~~"); 17 let sheet = sp.getSheetByName("~~"); 18 for(var i = 0; i < list.length; i++){ 19 sheet.appendRow(list[i]); 20 } 21}

html

1//webapp.html 2<!DOCTYPE html> 3<html> 4 <head> 5 <base target="_top"> 6 </head> 7 <body> 8 <button onClick="runInParallel()">並列実行</button> 9 <script> 10 const limit = 30; 11 12 function runInParallel() { 13 for (let i = 0; i < limit; i++) { 14 google.script.run.myFunction(i); 15 } 16 } 17 18 </script> 19 </body> 20</html> 21

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YAmaGNZ

2023/08/27 22:18

LockServiceを利用しての排他処理を行ってはどうでしょうか?
dedede914

2023/09/03 00:19

lockserviceを使ってみたんですがやはり上書きされてしまいます。 あとappendrowよりsetvaluesの方が処理速度が速いというご指摘をいただきましたので、だいたい700行ぐらいをひとまとまりでsetvaluesするように変えました。 どこがまずいですかね 上のjavascriptのwritedonを変更しました。 function writedown(list) { let sp=SpreadsheetApp.openById("~~~~~~~~~~"); let sheet = sp.getSheetByName(~); // スクリプトロックを取得する(この例では1分間トライする) const lock = LockService.getScriptLock(); if (lock.tryLock(60 * 1000)) { // 指定時間内にロックが取得できた場合は処理を実行 try { let lastrow=sheet.getLastRow(); let range=sheet.getRange(lastrow+1,1,lastrow+list.length,list[0].length); range.setValues(list); } catch(error) { // ロック取得以外のエラーが発生した場合 throw new Error(error.message); } finally { // ロックを解除 lock.releaseLock(); } } else { // 指定時間内にロックが取得できなかった場合はエラーを返す throw new Error("ロック取得タイムアウト"); } }
pecmm

2023/09/03 03:23

「ソースコード修正して問題点が一部改善された」ような状況であれば コメントではなく質問文そのものに追記した方が、回答者も現状把握しやすい&ソースが読み易くなります。
guest

回答2

0

「バルク処理に変えて、処理時間は問題なくなった」かつ「ロック取得しているはずが、上書きが発生している」という状態であれば、
range.setValues した後に SpreadsheetApp.flush するだけで良いかもしれません。

投稿2023/09/03 03:32

pecmm

総合スコア760

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

「たくさんデータを書き込みたい」→「GASの6分制限を超える」→「並列処理にしよう」
という話であれば、そもそも

「たくさんデータを書き込みたい」→「GASの6分制限を超える」の原因は appendRow 処理は遅い ということに尽きます。

つまり並列処理そのものが目的でなければ、別の解決策の方が簡単かもしれません。

解決策:全行一括処理

あまりデータ数が膨大でないのであれば、全部まとめて挿入という手があります。

javascript

1 let sheet = sp.getSheetByName("~~"); 2 let formula = `R2C1:R${list.length + 1}C3`; // 1行目はヘッダ―行として2行目から、3カラム決め打ちで左から埋める 3 let range = sheet.getRange(formula); 4 range.setValues(list);

現在の行から追記したいのであればgetlastRowしてその次の行からに変える等で対応します。

メリットは圧倒的に速いことですが
デメリットとしてはappendRowよりは考えなければいけないことが増え、デバッグも多少難しくなるでしょう。

(手元で確認したところ、100行=100回appendRowだと15秒かかりますが、一括処理であれば1000行でもまとめて1秒で終わります)

解決策:バルク処理

データが何十万行もあって一括処理の負荷が酷いとかであれば、指定行数ずつ扱うバルク処理に変えれば安定するかもしれません。

元データの行数&列数次第で、一気に扱えるデータ数は変わると思いますが
たとえば3600行を1000行ずつ処理するのであれば
[0, 1000]処理、[1001,2000]処理、[2001,3600]処理…の3分割というイメージです。
全行一括処理のサンプルコードの formula を上手に設定しながらループ処理するように改造する必要があります。

メリットは速さとデータ数に依存せず安定することの両立ですが
デメリットとして処理範囲を分割するためにもうちょっと難しくなります。

おまけ:さらに並列処理

さらに並列処理もしたくなった場合
上記のように行を指定した処理ができるなら、並列処理でも各スレッドに自分の書き込み先範囲を限定させれば一切干渉しなくなると思います
(これは試したことないので多分大丈夫なのでは?程度ですが……)

投稿2023/08/28 01:44

編集2023/08/28 01:45
pecmm

総合スコア760

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dedede914

2023/09/03 00:09

回答ありがとうございます!いくつかの手法があるのですね! setvaluesでデータ挿入に変更しましたが、スクレイピングした膨大なデータを扱うため、依然すべてのデータを挿入するとなれば並行処理が得策かと思っています! 質問へのコメントのところで現在の状況を書きましたのでぜひ確認いただけたらと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問