- PR -

[ASP.NET VB.NET]シングルトンはこれで大丈夫?

1
投稿者投稿内容
Ten.
ベテラン
会議室デビュー日: 2003/04/03
投稿数: 67
投稿日時: 2004-06-11 19:32
ASP.NETでアプリケーションの設定情報を保持するため、シングルトンを利用しようと思っています。
(環境:.NET Framework1.1 VS.NET2003 VB.NET)

設定情報は Web.config にあり、それをシングルトンのクラスに持たせようと思っています。

以下のようなクラスを作り、Webフォームで設定値を取得するテストをしてみました。

コード:
Imports System.Configuration

Public Class AppConfig

    Private Shared ReadOnly sigleton As AppConfig = New AppConfig

    Private hogeValue As String

    Private Sub New()
        Me.hogeValue = ConfigurationSettings.AppSettings("Hoge")
    End Sub

    Public Shared ReadOnly Property Instance() As AppConfig
        Get
            Return AppConfig.sigleton
        End Get
    End Property

    Public ReadOnly Property Hoge() As String
        Get
            Return Me.hogeValue
        End Get
    End Property

End Class



問題なく動作しているようですが、気になる点があります。

1.これはスレッドセーフになっているのか?
今までスレッドセーフにしなければならないようなプログラムを作ったことがないので、
いまいち自信がないです。
また、スレッドセーフになっているかどうかということをテストすることはできるのでしょうか?

2.シングルトンのインスタンスが破棄されるのはいつ?
最初は、クラスフィールドに格納されているので、OSがシャットダウンされるまでシングルトンの
インスタンスは破棄されないのでは?と思っていました。
ところが、Web.config を変更するとシングルトンのインスタンスが破棄されているようなのです。
(変更後にテストページにアクセスすと、変更後の値が取得される)
これは「Web.configを変更 > ワーカープロセスが再起動 > シングルトンのインスタンスが破棄」
ということなのでしょうか?

よろしくお願いします。
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2004-06-11 23:35
引用:

Ten.さんの書き込み (2004-06-11 19:32) より:
1.これはスレッドセーフになっているのか?
今までスレッドセーフにしなければならないようなプログラムを作ったことがないので、
いまいち自信がないです。
また、スレッドセーフになっているかどうかということをテストすることはできるのでしょうか?


この構造だと、AppSettingsで返されるクラスがスレッドセーフになっているかによりますね。
まあ、この点は問題ないはずですが。
引用:

2.シングルトンのインスタンスが破棄されるのはいつ?
最初は、クラスフィールドに格納されているので、OSがシャットダウンされるまでシングルトンの
インスタンスは破棄されないのでは?と思っていました。
ところが、Web.config を変更するとシングルトンのインスタンスが破棄されているようなのです。
(変更後にテストページにアクセスすと、変更後の値が取得される)
これは「Web.configを変更 > ワーカープロセスが再起動 > シングルトンのインスタンスが破棄」
ということなのでしょうか?


クラスフィールドはOSがシャットダウンされるまで有効でしょうか?
そんなはずはないですね。
クラスフィールドは、アプリケーションドメインの寿命がきたらそこで終わりです。
単純に言えば、アプリケーションドメインという環境に、クラスフィールドが存在しているわけですから。

アプリケーションドメインの寿命≒ワーカープロセスの寿命と思ってください。ちょっと意味が違いますが、「感覚的」には取りあえずそのような感じに思ってもらってよいです。


まあ、もっとも気になるのは、なんで構成ファイルの値を保持するためにシングルトンを使おうとしているのか、だったりしますが…
Ten.
ベテラン
会議室デビュー日: 2003/04/03
投稿数: 67
投稿日時: 2004-06-13 14:32
なちゃさん、ご返答ありがとうございます。

引用:

この構造だと、AppSettingsで返されるクラスがスレッドセーフになっているかによりますね。
まあ、この点は問題ないはずですが。


今回のようなインスタンスフィールドを変更しないクラスならば、大丈夫ということですよね。

引用:

クラスフィールドはOSがシャットダウンされるまで有効でしょうか?
そんなはずはないですね。
クラスフィールドは、アプリケーションドメインの寿命がきたらそこで終わりです。
単純に言えば、アプリケーションドメインという環境に、クラスフィールドが存在しているわけですから。

アプリケーションドメインの寿命≒ワーカープロセスの寿命と思ってください。ちょっと意味が違いますが、「感覚的」には取りあえずそのような感じに思ってもらってよいです。


このあたりは、テストしながら自分でも理解が間違っていると気づきました。
言われてみれば、別々のプロセスから同じメモリ空間にアクセスすることになるわけで、その時点でおかしいことに気づかなければいけませんね。
アプリケーションドメインについても、こちらのサイトの「連載:明解.NETテクノロジ」にちょうど載っており、「何者」なのかだけはわかりました。

引用:

まあ、もっとも気になるのは、なんで構成ファイルの値を保持するためにシングルトンを使おうとしているのか、だったりしますが…


私が思いついた方法は以下の3つでした。

a.毎回構成ファイルを読みに行く
b.Application変数に保持する
c.シングルトンに保持する

パフォーマンスで考えれば「a < b < c」だと思います。
ただ、b と c でそれほど大きな差があるとは思っていません。

ですので「なぜか?」と言われると、個人的に「やってみたかった」というのが一番の理由になります。

この程度の理由でしかないので、「こういうやり方のほうがいい」とか「普通はそんなことしないね」など、ご指摘していただけると助かります。

よろしくお願いします。
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2004-06-13 15:09
引用:

Ten.さんの書き込み (2004-06-13 14:32) より:
a.毎回構成ファイルを読みに行く
b.Application変数に保持する
c.シングルトンに保持する

パフォーマンスで考えれば「a < b < c」だと思います。
ただ、b と c でそれほど大きな差があるとは思っていません。

ですので「なぜか?」と言われると、個人的に「やってみたかった」というのが一番の理由になります。


あ、色々試したり実験したりする事はとても有効だと思います。
※逆にこれをしない人は進歩が遅かったりしますよね。

で、a. b. c. の話ですが、.NET Framework の構成ファイル読み込みの動作として、

1.基本は最初に必要とされたときに読み込まれる(厳密なタイミングは知りませんが、ユーザコード開始時に、すでにファイルは読み込まれている可能性もあるように思います)。この時点でXMLファイルの読み込みは完了し、DOMが構築されている。
2.それ以降は、特定の構成セクションが必要となった段階で、その構成セクションハンドラが実行される。ここで例えばNameValueCollection等のインスタンスが作成され、キャッシュされる。
3.2度目に同じ構成セクションが必要となった場合は、2.でキャッシュされたオブジェクトが返される。

というような流れになります。
構成セクションとは、例えば<appSettings>等のタグ部分と思ってください。

この動作から見ると、AppSettingsに最初にアクセスした時点で、<appSettings>セクションの情報はNameValueCollectionに保存されています。以降キャッシュされたこのオブジェクトが返されるだけです。

従って、毎回ファイルが読み込まれるわけではなく、コレクションからのサーチが行われるだけです(構成セクション名から有効な構成ファイルのオブジェクトをサーチ+見つかったコレクションからのキーのサーチ)。

ここまで書いて見直してみたんですが、私、最初のプログラムを読み間違えていました。m(_ _)m
AppSettingsプロパティの値を保存しているんではなくて、特定のキーの値を保持してたんですね…。
上の私のスレッドに関する記述は間違いでした。AppSettingsなどには依存していませんね。m(_ _)m

この場合は、c.の方法だとキーから文字列をサーチする作業がなくなるので、少し効率はよくなります(シングルトンでなくても、単なるstaticな変数とかでもいいですが)。
※少しといっても実行に要する時間と言う意味では全然違いますね。

ただし、b.の方法では、同様に変数名のサーチが行われるためそれほどは効率はよくなりません。また、ロックが自動的にかかったはずなので、条件によってはむしろ効率は悪くなる可能性もあります。ただしこれは、構成セクションの読み込みとか、AppSettingsで返されるオブジェクトのスレッドセーフ性がどのように保証されているかによります。

[ メッセージ編集済み 編集者: なちゃ 編集日時 2004-06-13 15:16 ]
Ten.
ベテラン
会議室デビュー日: 2003/04/03
投稿数: 67
投稿日時: 2004-06-14 11:20
引用:

で、a. b. c. の話ですが、.NET Framework の構成ファイル読み込みの動作として、

1.基本は最初に必要とされたときに読み込まれる(厳密なタイミングは知りませんが、ユーザコード開始時に、すでにファイルは読み込まれている可能性もあるように思います)。この時点でXMLファイルの読み込みは完了し、DOMが構築されている。
2.それ以降は、特定の構成セクションが必要となった段階で、その構成セクションハンドラが実行される。ここで例えばNameValueCollection等のインスタンスが作成され、キャッシュされる。
3.2度目に同じ構成セクションが必要となった場合は、2.でキャッシュされたオブジェクトが返される。

というような流れになります。
構成セクションとは、例えば<appSettings>等のタグ部分と思ってください。

この動作から見ると、AppSettingsに最初にアクセスした時点で、<appSettings>セクションの情報はNameValueCollectionに保存されています。以降キャッシュされたこのオブジェクトが返されるだけです。

従って、毎回ファイルが読み込まれるわけではなく、コレクションからのサーチが行われるだけです(構成セクション名から有効な構成ファイルのオブジェクトをサーチ+見つかったコレクションからのキーのサーチ)。


毎回ファイルを読みに行くようなことはしてないだろうな、と漠然と思ってはいましたが、調べてはいませんでした。
そこで調べてみたら、MSDNの「ASP.NET の構成」の一番最初にちゃんと書いてありました。。。
MSDN ASP.NET の構成

せっかくなので、どれぐらいの差があるのか試してみました。
(ぐるぐる回して同じ設定値を取得するのにかかった時間を計っただけなので、どれだけの意味があるかは分かりませんが)

かかった時間の比率は以下のようになりました。
a:10 b:7 c:1

aが10倍遅いと言っても、1回の取得には100分の1msもかかっていないので、実際のアプリケーションでは無視できるレベルだと思います。

シングルトンで保持する方法で特に問題なさそうなので、これでやってみます。

いろいろとアドバイスをありがとうございました。

ちなみに、
引用:

この場合は、c.の方法だとキーから文字列をサーチする作業がなくなるので、少し効率はよくなります(シングルトンでなくても、単なるstaticな変数とかでもいいですが)。


staticな変数(クラスフィールドのことですね? C#をやっていてVB.NETは初めてなので、用語などの微妙な違いでよく混乱します)に保持する方法ですと、最初に値を設定するときにスレッドセーフになるようにする必要があるのでは?
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2004-06-14 13:05
引用:

Ten.さんの書き込み (2004-06-14 11:20) より:
staticな変数(クラスフィールドのことですね? C#をやっていてVB.NETは初めてなので、用語などの微妙な違いでよく混乱します)に保持する方法ですと、最初に値を設定するときにスレッドセーフになるようにする必要があるのでは?


あ、VB.NETではSharedですね。そう、クラスフィールドのことです。

これは実際には別にシングルトンとそう変わるわけではありません。
単にクラスのSharedフィールドとして設定値を持っておくというだけの話です。

Sharedフィールドの初期化時は当然スレッドセーフになっている必要がありますが、シングルトンの実装と同じで、イニシャライザや静的コンストラクタで行えばよいという話です。
※取得しようとした時点では既に初期化は済んでいるはずということですね。
1

スキルアップ/キャリアアップ(JOB@IT)