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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Google App Engine

Google App Engineは、Googleの管理するデータセンター上でウェブアプリケーションの開発が可能なクラウドコンピュータ技術です。Java、Python、Go用にSDKが用意されています。

Q&A

解決済

1回答

2187閲覧

【GAE/Go】initでのDatastoreへのアクセス

musharna000

総合スコア18

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Google App Engine

Google App Engineは、Googleの管理するデータセンター上でウェブアプリケーションの開発が可能なクラウドコンピュータ技術です。Java、Python、Go用にSDKが用意されています。

0グッド

1クリップ

投稿2015/08/03 16:49

Google App Engine for Go を利用してWebサービスを開発しています。
Datastoreへのアクセスを減らすために、
リクエスト毎にDatastoreにクエリをとばすのではなく、
init関数内で読み込んでおきそれを利用しようと考えています。

しかしながら、Datasotreへのアクセスに利用する
appengine.Contextの取得(func NewContext(req *http.Request) Context)をするのに
http.Requestが必要なため、httpリクエストがあった時しか
Datastoreへのアクセスができないので困っています。

対処法として、
データを読み込んだかをbool型のグローバル変数で記録して、
httpリクエストがあった際にこれをチェックして
まだ読み込まれていなかったらDatastoreから読み込む、
という方法を考えたのですが、
httpリクエストをハンドルしている関数ひとつひとつに
このためのif文を書き込むというのがスマートでなく感じたのと
読み込んでいないときに同時にアクセスがあった場合に
二重に読み込まれるなど危ない事になりそうだと考え
他に何か方法がないかと考えている次第です。

何か代替する方法はありますでしょうか。
皆様の知識をお借りしたいです。

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

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

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

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

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

guest

回答1

0

ベストアンサー

Singletonパターンを適用してみてはいかがでしょうか。

go

1package singleton 2 3import ( 4 "net/http" 5 "sync" 6) 7 8type singleton struct { 9 //ここでDatastoreから取得したデータを保持 10} 11 12var instance *singleton 13var once sync.Once 14 15func newSingleton(r *http.Request) *singleton { 16 s := new(singleton) 17 // ここでGAEを用いてDatastoreからデータを取得する 18 return s 19} 20func GetInstance(r *http.Request) *singleton { 21 once.Do(func() { 22 instance = newSingleton(r) // <-初回呼び出し時のみここが呼ばれる 23 }) 24 return instance 25}

ハンドラ側からの呼び出しコードは以下のようになります。

go

1func SomeHandler(w http.ResponseWriter, r *http.Request) { 2 data := singleton.GetInstance(r) 3 // データを使用した処理 4}

出典:
Singleton Pattern in Go(英文)
http://marcio.io/2015/07/singleton-pattern-in-go/

投稿2015/08/03 23:56

編集2015/08/04 00:10
hy3

総合スコア594

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

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

musharna000

2015/08/04 12:15

回答ありがとうございます。 シングルトンで書けばスレッドセーフできますね!思いつきませんでした。 追加での質問になってしまい申し訳ないのですが、 このパターンでinstanceの生成に失敗した場合(Datastoreへのアクセスで何かあった場合) ひとまずそのリクエストには500(Internal Server Error)でも返しておいて 次のリクエストでもう一度トライするという形にしたい場合はどうしたらいいでしょうか。 sysc.Onceを調べてみたもののOnceをリセットするような関数は見つからなくて....... 宜しくお願いします。
hy3

2015/08/04 14:58 編集

sync.Onceのソースコードを読む限り、リセットするにはプライベートメンバであるOnce.doneを書き換える必要があり、パッケージ外からリセットするのは難しそうです。 unsafeパッケージを駆使すれば不可能ではないとは思いますが、あまりお勧めはできません。 次善の策としては、Once構造体を作り直すという手がありそうです。 package singleton // 省略 func Reset() { once = sync.Once{} } どちらにせよ、once.Doが呼ばれてからリセットまでの間に次のリクエストが発生すると、 GetInstanceがnilを返す可能性が残ります。完全なスレッドセーフを目指すならばもう一工夫必要そうですね・・・。
musharna000

2015/08/12 11:40

返信送れてしまい申し訳ありません。 スレッドセーフな書き方についてもう少し勉強してみようと思います。 とても助かりました。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問