2009-05-18 9 views
2
class ApplicationContext{ 
    private final NetworkObject networkObject = new networkObject(); 

    public ApplicationContext(){ 
     networkObject.setHost("host"); 
     networkObject.setParams("param"); 
    } 

    public searchObjects(ObjectType objType){ 
     networkObject.doSearch(buildQuery(objType)); 
    } 
} 

class NetworkObject{ 
    private final SearchObject searchObject = new SearchObject(); 

    public doSearch(SearchQuery searchQuery){ 
     searchObject.search(searchQuery); //threadsafe, takes 15(s) to return 
    } 
} 

1つのApplicationContextインスタンス(シングルトン)を作成し、同じapplicationInstanceを使用してsearchObjectを呼び出すWebアプリケーションを実行しているWebサーバーを考えてみましょう。複数のスレッドがWebアプリケーションを高速化するように見えないのはなぜですか?

ApplicationContext appInstance = 
        ApplicationContextFactory.Instance(); //singleton 

Webページへのすべての新しい要求が 'search.jsp' と言う私は 'search.jsp' のページに1000の要求を作っていますコール

appInstance.searchObjects(objectType); 

になります。すべてのスレッドが同じApplicationContextインスタンスを使用しています。また、searchObject.search()メソッドは15秒かかるので返します。私の質問は、他のすべてのスレッドがsearchObject.search()関数を実行しているとき、またはすべてのスレッドが同時にsearchObject.search()を同時に実行しているときに、そのターン(15秒)が実行されるのを待ちますか?

私は私の質問を非常に明確にしたいと思っていますか?

更新: ご迷惑をおかけしていただきありがとうございます。

public synchronized doSearch(SearchQuery searchQuery){ 
    searchObject.search(searchQuery); //threadsafe, takes 15(s) to return 
} 

OR

public doSearch(SearchQuery searchQuery){ 
    searchObject.search(searchQuery); //threadsafe, takes 15(s) to return 
} 

私は同期キーワードを指定せずに関数「doSearch」を使用して、よりパフォーマンスを与えるべきであると考えている。ここに私の2番目の質問は、私が行うときに観察されなければならない性能にどのような違いであり、 。しかし、私が今日それをテストしたとき、結果は逆になりました。同期されたキーワードを使用すると、パフォーマンスは似ています。

誰でも行動を説明できますか?そのようなケースをどのようにデバッグするべきですか?

よろしく、

ペリー

答えて

5

私は、すべてのスレッドが同時に実行されると思われるだろうと、他の証拠のないように、さてあなたは、コードに任意の同期化を指定していません。 SearchObject.searchに何らかの同期が含まれていると、同時性が明らかに制限されます。

JSPコンテナはスレッドスレッドを1000個作成するのではなく、1000個の要求を処理するスレッドプールを使用している可能性があります。

編集:​​の方が速い理由について:並行処理はスループットに実際に役立たないことがあります。コンテキスト切り替え、ディスクのボトルネック、キャッシュミスなどのようなものは、その効果があります。 通常はコアより多くのスレッドを実行することはお勧めできません。

実際の例では、かなり小さな店から買い物をしたい千人の買い物客がいるとします。それについてどうやって行きますか?同時に1000店舗をすべて店内に置くか、いつでも店内でかなり小さい数にしておきます。

+0

上記の私の更新を見てください! – pankajt

0

あなたの場合、それらはすべて同時に実行されます。

これを防ぐには、同期を防止する(ロックを使用するなどの方法を避ける)必要があります。

ETA:

同期としてあなたがdoSearch()メソッドを宣言すると、一度に一つのスレッドだけがそれを呼び出すことができます。他のスレッドは、最初のスレッドが終了するまでブロックされ、待機スレッドは一度に1つずつ「取り込み」されます。あなたが想像することができるように、多くのスレッドがその関数を呼び出すと、これはあなたのパフォーマンスを殺します。

+0

上記の私の更新をご覧ください! – pankajt

0

同期がない場合、各スレッドは同時に実行され、ロックをブロックしません。それがスレッドをブロックしますないを - (コメントとして)

// threadsafe 

が、それは、複数のスレッドがそれにアクセスすると正常に動作します意味

注意。

+0

上記の私の更新をご覧ください! – pankajt

0

クラスがシングルトンIIRCであるという事実にかかわらず、それらはsynchronizedとして宣言されていない限り、すべて同時に実行できます。

+0

上記の私の更新をご覧ください! – pankajt

0

SearchObject.searchが同期されている場合は、yesです。それ以外の場合は、試してみてください。

+0

上記の私の更新をご覧ください! – pankajt

0

なぜ15秒かかりますか?それがディスクアクセスを待っていて、ディスクが1つしかない場合は、スレッドの数に関係なく、ディスクのシーク速度によって制限されます。この状況では、より多くのスレッドがさらに遅くなることさえあります。

+0

すべてのスレッドがディスクアクセスを待っていると、パフォーマンスが低下することに同意します。 search()メソッドが返す時間が非常に短いと仮定すると、ここではパフォーマンスが同期にどのように影響するかを知りたいです – pankajt

1

パフォーマンスは特定の環境に関するものであることを理解することは賢明です。この場合、おそらくラップトップまたはテストサーバー上のソフトウェアのパフォーマンスです。コードの最適化を検討する前でも、開発環境とはかなり異なるボトルネックがあるため、実稼働環境に似たものでパフォーマンスをチェックすることをお勧めします。

例として、ラップトップで大規模なデータベースを使用してソフトウェアをテストすると、いつもハードディスク-IOに縛られてしまいます。しかし、本番環境では、データベースサーバーには十分なメモリと高速ディスクがあるため、ソフトウェアをIO用に最適化することは賢明ではありません。

スレッドと同様です。私のラップトップのプロセッサは、1つまたは2つのプロセスを同時に実行できます。 8つのスレッドを持つことは物事をスピードアップしません。しかしながら、生産マシンは同時に8つのスレッドを同時に処理できる可能性があります。

パフォーマンスよりも重要なのはセマンティクスです。同期のようなキーワードを使用することは、コンパイラだけでなく、(次の)開発者にも有益です。

同期を使用すると、ApplicationContext上の他のすべての同期メソッドとロックを共有します。また、searchObjectとは何の関係もないメソッドもロックを共有します。 個人的には、ApplicationContextというオブジェクトを同期させたいと思っています。

searchObjectがスレッドセーフでない場合は、おそらくロックオブジェクトをお勧めします。これは味にしています:

public void doSearch(SearchQuery searchQuery){ 
    synchronized(searchObject) {// Only if searchObject is guaranteed to be null 
     searchObject.search(searchQuery); //threadsafe, takes 15(s) to return 
    } 
} 

または

public class ApplicationContext { 
    private SearchObject searchObject = null; 
    private final Object searchObjectLock = new Object();  

    public void doSearch(SearchQuery searchQuery){ 
     synchronized(searchObjectLock) { 
      searchObject.search(searchQuery); //threadsafe, takes 15(s) to return 
     } 
    } 
} 

はスレッドトラブルを防ぐためにsearchObjectのすべての使用をロックすることを忘れないでください。このきめ細かいロック機構を使うことで、少なくともApplicationObject関連の機能を必要としないクラスでApplicationContextを利用できるようにすることができます。

あなたのケースでは、ボトルネックを特定する前に、私はそれが必須ではないため、同期を使用せず、実動のようなハードウェアをチェックします。

また、searchObjectがデータベースを使用する場合は、データベースのプロパティがインデックスに登録され、そのインデックスが使用されていることを確認してください。 1000台のフルテーブルスキャンを行う必要がある場合、それは速くはありません...

+0

パフォーマンスはハードウェアに調整されています。しかし、一般的な規則や原則として、私たちは特定のガイドラインに従っています。私はコアの数に等しい数のスレッドを持っていることに関してJonに同意します – pankajt

+0

ええ、それはパフォーマンス分析の基礎となる開発システムではなく、本番システム上のコアの数です。 – extraneon

関連する問題