3

私の現在のアプリケーションは、オブジェクトの単一インスタンスを多くの主要コンポーネントのグローバル変数として使用していますが、これは依存性注入を使用するよりも劣っていると考えられています。

将来は自分のアプリケーションをオープン ソースにしたいと考えていますが、最初にコードをリファクタリングして、チーム コラボレーションに最も推奨される手法を使用し、他の開発者が自分のソース コードをより簡単に変更できるようにしたいと考えています。

共有リソースの例: CFML 言語では、サーバー スコープがあります。これは、サーバー インスタンス全体のすべての要求に使用できる共有メモリです。

サーバー スコープへの変更を管理するための新しい設計コンセプトは次のとおりです。

  1. サーバー スコープへの書き込みおよび読み取り用のインターフェイスを提供する ServerMemoryManager という名前のコンポーネントの単一インスタンスを作成します。
  2. サーバー スコープにアクセスする必要があるその他のコードには、init() 関数または setServerMemoryManager() 関数を介して ServerMemoryManager の単一インスタンスへの参照が挿入されます。
  3. コンポーネントが ServerMemoryManager オブジェクトに対してデータの読み取り/書き込みを行うときは常に、サーバー スコープを内部的にロックできるため、2 つのスレッドがサーバー スコープ内の同じメモリに同時に書き込むことはできません。

これは、スレッドセーフにするためにロックが必要な共有リソース (共有メモリ、ファイルシステムなど) を管理するための最良の方法ですか?

ベスト プラクティスと見なされる特定の読み取り/書き込み操作中にロックを必要とする共有リソースを管理するために使用できる追加の方法について説明してください。

編集: scope="server" をロックする代わりに、受け入れられた回答に基づいて、名前付きロックを使用し、よりきめ細かいロックで共有リソースを管理します。これにより、共有メモリ内の異なるキーまたはファイルシステム内のファイルをすべて管理していると仮定して、複数のオブジェクトを使用して共有リソースを管理できるようになります。たとえば、あるアプリケーションに独自の一意のキーまたはディレクトリを割り当てて、共有リソースを変更しようとしている別のアプリケーションと競合しないようにすることができます。

Edit2:オブジェクトを作成するときにスコープを init 関数に渡すと、スコープごとに scope.cfc という名前の単一のコンポーネントを使用できることがわかりました。現在、きめの細かい名前付きロックを使用しています。改善できるかどうか教えてください。実際に修正されたコードは次のようになります (read、delete、clear のコードは除外しました)。また、scope.cfc コンポーネントのインスタンスを 1 つだけ持つ必要もなくなったようです。

            <cfcomponent>
                <cfscript>
                variables.scope=false;
                variables.scopeName=false;
                </cfscript>
                <cffunction name="init" access="public" output="no" returntype="scope">
                    <cfargument name="scope" type="struct" required="yes">
                    <cfargument name="scopeName" type="string" required="yes">
                    <cfscript>
                    variables.scope=arguments.scope;
                    variables.scopeName=arguments.scopeName;
                    return this;
                    </cfscript>
                </cffunction>
                <cffunction name="write" access="public" output="no" returntype="boolean">
                    <cfargument name="key" type="string" required="yes">
                    <cfargument name="value" type="any" requires="yes">
                    <cfargument name="timeout" type="numeric" required="no" default="10">
                    <cftry>
                        <cflock type="exclusive" name="zcore-#variables.scopeName#-scope-#arguments.key#" timeout="#arguments.timeout#" throwontimeout="yes">
                            <cfscript>
                            variables.scope[arguments.key]=arguments.value;
                            </cfscript>
                        </cflock>
                        <cfcatch type="lock"><cfreturn false></cfcatch>
                    </cftry>
                    <cfreturn true>
                </cffunction>
            </cfcomponent>

** Edit3:** このようなコンポーネント メソッドを使用してサーバー スコープから読み取るパフォーマンスをテストしたところ、読み取り専用ロックを使用するとサーバー スコープを直接読み取る場合よりも 20 倍遅く、ロックなしで 4 倍遅くなることがわかりました。リクエストごとに数百回または数千回の追加の関数呼び出しのオーバーヘッドは遅すぎます。Railo 3.3.x で行われたテスト。

非パブリック リクエストで大きなオブジェクトを構築し、単一の共有メモリ スコープ キーを設定してから、不完全なオブジェクトをスコープに書き込もうとします。例:

<cfscript>
ts=structnew();
ts.largeObject=buildLargeObject();
server.cachedObject=ts;
</cfscript>

これにより、単一の構造体キーの更新はスレッドセーフであるため、完全なオブジェクトのみを共有メモリに書き込む場合に、アプリケーション全体でのロックを回避できます。ただし、起動時にラージ オブジェクトをビルドする場合は、そのオブジェクトが完全に作成されるまで、オブジェクトがロックされていることを確認する必要があります。

アプリケーションの速度低下を避けるために、init 関数で変数スコープの代わりに this スコープを使用して、スコープ変数を直接読み取り可能にします。

4

1 に答える 1

2

CFLOCKは、すべてのオカレンスが同じ方法でロックされている場合にのみ、コードの実行を防ぎます。

例えば:

page1.cfm

<cflock type="exclusive" scope="server" timeout="10" >
   <cfset application.xyz = 'abc'>
</cflock>

page2.cfm

<cfset application.xyz = '123'>

page2がpage1と同じ時間に実行される場合、Page2.cfmはpage1.cfmにあるロックを無効にします。とはいえ、各オブジェクトをロックする必要がないように、cfc内でロックしているのは良いことです。

ただし、すべてのオカレンスをロックするだけでは不十分です。以下もあまり役に立たないでしょう。

page1.cfm

<cflock type="exclusive" scope="server" timeout="10" >
   <cfset application.xyz = 'abc'>
</cflock>

page2.cfm

<cflock type="exclusive" scope="server" timeout="10" >
   <cfset application.xyz = '123'>
</cflock>

これにより、page1とpage2のすべての要求の処理が停止しますが、page1のapplication.xyzは、page2のapplication.xyzに加えられた変更から保護されません。これを行うには、ロックに「名前」を付ける必要があります

名前をロックします。scope属性と相互に排他的です。一度に指定された名前のcflocktag内でコードを実行できるリクエストは1つだけです。空の文字列にすることはできません。

アプリケーションのさまざまな部分からのリソースへの同期アクセスを許可します。ロック名はColdFusionサーバーに対してグローバルです。これらはアプリケーションとユーザーセッション間で共有されますが、クラスター化されたサーバーでは共有されません。

オブジェクトの複数のインスタンスを作成しているため、ロックに名前を付けない限り、serverMemoryManagerObject干渉する可能性があると思います。serverMemoryManagerObject2

ここに、すべきこととすべきでないことのロックに関するいくつかの詳細情報があります

于 2012-11-02T12:32:09.593 に答える