2013-03-26 15 views
5

私はいくつかの線形代数コードを書いています(Fortran 2003ではFortran 90やCで同じ問題になります)。計算にはいくつかの作業ベクトルが必要です。これに対処する私の考えは、配列w(:,:)は、線形代数モジュールに対してプライベートです。すなわち、なぜ真のグローバル変数がひどいのかをthis discussionで定義された「隠されたグローバル」です。は、隠されたグローバルな悪いプログラミング練習ですか?

私はこれを黒板で解くのに大きな問題があると想像し、問題の各部分については黒板の領域を選んで解決します。

このようにして、小さなホワイトボードがたくさんある場合もあります。work_arrayデータ型を定義し、必要に応じてソルバーに渡します。 (PETScは、このアプローチを別の抽象レイヤーで効果的に使用します; solverは、使用されるメソッドへのいくつかの手続きポインターといくつかの作業ベクトルを含むデータ型です)。あるソルバーから他のソルバーにネストされた呼び出しがある場合、複雑なダニなので、私は最初の方法がより好きです。また、間違った指示を必要としません。

どのアプローチを使用してプログラミングを改善するかについての考えはありますか?

EDIT:このコードの古い化身ですでに行っているOpenMPの使用を開始すると、問題になるとは思われません。各スレッドは、問題が設定された後、未知の部分だけにアクセスし、他のスレッドの部分にはアクセスしません。それにもかかわらず、並行性の問題はおそらく静的変数を一般的に使用しないのに十分な理由です。

ソルバーを呼び出すたびにスクラッチアレイの領域を動的に割り当てておく必要がある場合は、オーバーヘッドが大きくなることはありませんか?

+2

複数のスレッドが一度にアクセスしようとするとどうなりますか? – Mysticial

+1

どのような利点がありますか?作業スペースが小さい場合は、自動化してください。それが巨大であれば、mallocと必要に応じて無料です。 –

答えて

6

あなたが作業スペース内の任意の非自明な計算をやっている場合は、mallocfreeのコストが割り当てられたスペースで実行される計算のコストによって支配され、オーバーヘッドはほぼゼロになります。割り当てを回避することが最適化戦略として理にかなっているのは、バッファ上で実行される作業の量が非常に少なく、バッファを取得する時間が支配的になる(または少なくとも別の用語が支配しない場合がある)場合のみです。これが起こる主な状況は、文字列を構築することです。一方

、グローバル状態は、コストをたくさん持っている:

  1. それはマルチスレッド使用を排除します。
  2. 複数の呼び出しの間に状態を維持する必要がある場合、ライブラリの使用が排除されます(ライブラリは、互いの作業を壊す可能性があるため、一度に複数のプログラムで使用できません)。
  3. 再帰的/再入可能な使用を排除します。
  4. 関数が呼び出されなくても、ライブラリがリンクされているときはいつでもメモリを使用します。
  5. これらの問題のいくつかを回避するように努力しても、深刻なコードの臭気であり、したがって人の時間でのコードグローバル状態が実際にコードにバグや使用制限を導入しているかどうかを判断しようとしている間に、コードを読む次の人の時間を無駄にします。
+0

あなたは私に確信しています。 – korrok

5

「隠されたグローバル」(Cの世界ではstaticと呼ばれる)の最大の危険は、並行プログラムを書くときに来ることです。ひとたびマルチスレッド化すると、単一の黒板ではもはや十分ではありません。各スレッドは独自のものを必要とします。このような状況では、動的割り当てがより適切です。マルチスレッド化について心配しなければ、モジュールスコープの「隠されたグローバル変数」は完全にうまくいきます。

1

割り当てコストについて:すべての作業配列(あなたの場合は配列w(:,:))を含む派生型を持つことができます。あなたは正しいサイズにそれらを割り当て、1つの初期化コールを、持っている、そして、できるだけ多くの場合、以下の精神で何かソルバーにその中に割り当てられた配列を持つ派生型を渡すことができます。

module test 
    implicit none 

    type :: buffer 
     integer, allocatable :: work(:,:) 
    end buffer 

contains 

    subroutine init(mybuffer, whatever_else_you_need_for_determinig_allocation_size) 
     type(buffer), intent(out) :: mybuffer 

     allocate(mybuffer%work(dim1, dim2)) 
    end subroutine init 

    subroutine solver(mybuffer, whatever_else_you_need_for_the_solver) 
     type(buffer), intent(inout) :: mybuffer 

      ! You can access mybuffer%work here as it is allocated 

     end subroutine solver 

end module test 

しかしなどをすでに指摘されていましたが、ソルバーで費やすコストに関しては、割り当てコストは通常​​無視されます。

関連する問題