2012-03-11 16 views
3

複数のスレッドが静的メソッドにアクセスする方法を説明できますか?複数のスレッドが静的メソッドに同時にアクセスできますか?静的メソッドとインスタンスメソッド、マルチスレッド、パフォーマンス

私には、メソッドが静的であれば、すべてのスレッドで共有される単一のリソースにすることが論理的であるように見えます。したがって、一度に使用できるスレッドは1つだけです。私はこれをテストするコンソールアプリケーションを作成しました。しかし、私のテストの結果から、私の前提は間違っているように見えます。

私のテストでは、多くのWorkerオブジェクトが構築されています。各Workerにはいくつかのパスワードとキーがあります。各Workerには、そのパスワードでパスワードをハッシュするインスタンスメソッドがあります。まったく同じ実装を持つ静的メソッドもありますが、唯一の違いは静的メソッドだけです。 Workerオブジェクトがすべて作成された後、開始時刻がコンソールに書き込まれます。その後、DoInstanceWorkイベントが発生し、WorkerオブジェクトのすべてがuseInstanceMethodをスレッドプールにキューイングします。すべてのメソッドまたはすべてのオブジェクトが完了すると、すべてが完了するまでに要した時間が開始時刻から計算され、コンソールに書き込まれます。その後、開始時刻が現在の時刻に設定され、DoStaticWorkイベントが発生します。今回は、すべてWorkerオブジェクトがuseStaticMethodをスレッドプールにキューイングします。これらのメソッド呼び出しがすべて完了してから完了するまでの時間が再び計算され、コンソールに書き込まれます。

オブジェクトがインスタンスメソッドを使用する時間が、静的メソッドを使用する時間の1/8になると予想していました。私のマシンは4つのコアと8つの仮想スレッドを持っているため1/8です。しかし、そうではありませんでした。実際、静的メソッドを使用するときの時間は実際には分けて速かったです。

これはどのようにですか?フードの下で何が起こっていますか?各スレッドは静的メソッドの独自のコピーを取得しますか?ここで

は、あなたがそれを防ぐために、明示的な仕事をしていない限り、静的またはインスタンス、いずれかのスレッドが任意の時点で任意のメソッドにアクセスできるかどうか、すべての場合において、コンソールAPP-

using System; 
using System.Collections.Generic; 
using System.Security.Cryptography; 
using System.Threading; 

namespace bottleneckTest 
{ 
    public delegate void workDelegate(); 

    class Program 
    { 
     static int num = 1024; 
     public static DateTime start; 
     static int complete = 0; 
     public static event workDelegate DoInstanceWork; 
     public static event workDelegate DoStaticWork; 
     static bool flag = false; 

     static void Main(string[] args) 
     { 
      List<Worker> workers = new List<Worker>(); 
      for(int i = 0; i < num; i++){ 
       workers.Add(new Worker(i, num)); 
      } 
      start = DateTime.UtcNow; 
      Console.WriteLine(start.ToString()); 
      DoInstanceWork(); 
      Console.ReadLine(); 
     } 
     public static void Timer() 
     { 
      complete++; 
      if (complete == num) 
      { 
       TimeSpan duration = DateTime.UtcNow - Program.start; 
       Console.WriteLine("Duration: {0}", duration.ToString()); 
       complete = 0; 
       if (!flag) 
       { 
        flag = true; 
        Program.start = DateTime.UtcNow; 
        DoStaticWork(); 
       } 
      } 
     } 
    } 
    public class Worker 
    { 
     int _id; 
     int _num; 
     KeyedHashAlgorithm hashAlgorithm; 
     int keyLength; 
     Random random; 
     List<byte[]> _passwords; 
     List<byte[]> _keys; 
     List<byte[]> hashes; 

     public Worker(int id, int num) 
     { 
      this._id = id; 
      this._num = num; 
      hashAlgorithm = KeyedHashAlgorithm.Create("HMACSHA256"); 
      keyLength = hashAlgorithm.Key.Length; 
      random = new Random(); 
      _passwords = new List<byte[]>(); 
      _keys = new List<byte[]>(); 
      hashes = new List<byte[]>(); 
      for (int i = 0; i < num; i++) 
      { 
       byte[] key = new byte[keyLength]; 
       new RNGCryptoServiceProvider().GetBytes(key); 
       _keys.Add(key); 

       int passwordLength = random.Next(8, 20); 
       byte[] password = new byte[passwordLength * 2]; 
       random.NextBytes(password); 
       _passwords.Add(password); 
      } 
      Program.DoInstanceWork += new workDelegate(doInstanceWork); 
      Program.DoStaticWork += new workDelegate(doStaticWork); 
     } 
     public void doInstanceWork() 
     { 
      ThreadPool.QueueUserWorkItem(useInstanceMethod, new WorkerArgs() { num = _num, keys = _keys, passwords = _passwords }); 
     } 
     public void doStaticWork() 
     { 
      ThreadPool.QueueUserWorkItem(useStaticMethod, new WorkerArgs() { num = _num, keys = _keys, passwords = _passwords }); 
     } 
     public void useInstanceMethod(object args) 
     { 
      WorkerArgs workerArgs = (WorkerArgs)args; 
      for (int i = 0; i < workerArgs.num; i++) 
      { 
       KeyedHashAlgorithm hashAlgorithm = KeyedHashAlgorithm.Create("HMACSHA256"); 
       hashAlgorithm.Key = workerArgs.keys[i]; 
       byte[] hash = hashAlgorithm.ComputeHash(workerArgs.passwords[i]); 
      } 
      Program.Timer(); 
     } 
     public static void useStaticMethod(object args) 
     { 
      WorkerArgs workerArgs = (WorkerArgs)args; 
      for (int i = 0; i < workerArgs.num; i++) 
      { 
       KeyedHashAlgorithm hashAlgorithm = KeyedHashAlgorithm.Create("HMACSHA256"); 
       hashAlgorithm.Key = workerArgs.keys[i]; 
       byte[] hash = hashAlgorithm.ComputeHash(workerArgs.passwords[i]); 
      } 
      Program.Timer(); 
     } 
     public class WorkerArgs 
     { 
      public int num; 
      public List<byte[]> passwords; 
      public List<byte[]> keys; 
     } 
    } 
} 

答えて

8

メソッドはコードです。スレッドはコードを実行することによってコードが変更されないため、コードに同時にアクセスすることは問題ありません。読み取り専用のリソースです(ジッタを除いて)。マルチスレッド環境で慎重に処理する必要があるのは、データへの同時アクセスです(具体的には、そのデータの変更が可能な場合)。メソッドがstaticであるかインスタンスメソッドであるかは、スレッドセーフにするために何らかの方法で直列化する必要があるかどうかとは関係ありません。

+1

コード対データ+1。 –

+0

読み取り専用リソースであるメソッドについての説明をありがとう。私は、私の理解の大きな違いは、同じリソースを同時に多くのスレッドがどのように読むことができるかということです。私はコンピュータの基本的な理解にかなり基本的だと思います。私は無意識のうちに、実際には多くのスレッドで何度も読むことができると思ったときに、メソッドが1クロックサイクルに1回しか読み込めないと思っていました。しかし、すべてが1クロックサイクル内に発生するため、読み込みが並行しているように見えるのは本当ですか?また、メソッドの読み込み方法は?すべて一度に、またはセクションで?ありがとう –

4

です。

例えば、ロックを作成して、1つのスレッドだけが特定のメソッドにアクセスできるようにすることはできますが、C#はそれを実行しません。

テレビを見ているような気がします。テレビは、複数の人が同じ時間にそれを見るのを防ぐために何もしません。同じ番組を見たいと思っているすべての人が同じ番組を見たい限り、問題はありません。あなたは確かに、複数の人々が異なるショーを見たいかもしれないので、テレビがただ一人でそれを見ることを許すことを望んでいませんか?だから、人々は別のショーを見たいと思っているならば、テレビ自体の外に何らかの仕組みが必要です(おそらく、現在の視聴者がショーの期間中保持している1つのリモートコントロールを持つ)別の男が見ている間、彼のショーへのチャンネル。

1

インスタンスメソッドにアクセスするときは、オブジェクト参照によってアクセスしています。

静的メソッドにアクセスする場合、静的メソッドに直接アクセスしています。

静的メソッドは非常に高速です。

0

クラスをインスタンス化するときは、コードのコピーを作成しないでください。クラスの定義へのポインタがあり、そのコードにはそのコードが付属しています。したがって、インスタンスメソッドは静的メソッドよりも穏やかな方法でアクセスされます

3

C#メソッドは「リエントラント」です(ほとんどの言語と同様、真に非リエントラントなコードはDOSルーチンでした)。各スレッドには独自の呼び出しスタックメソッドが呼び出されると、そのスレッドの呼び出しスタックは、戻りアドレス、呼び出しパラメータ、戻り値、ローカル値などのためのスペースを持つように更新されます。

スレッド1とスレッド2が同時にメソッドMを呼び出し、Mローカルint変数nを持ちます。 Thread1の呼び出しスタックはThread2の呼び出しスタックから分離しているので、nは2つの異なるスタックに2つの異なるインスタンス化を持ちます。並行処理は、nがスタックに格納されていないのに同じレジスタ(つまり共有リソース)内にあるCLR(またはWindows?)で問題が発生しないように注意し、スレッドを切り替えるときのレジスタ(複数のCPUがある場合はどのようにして、どのようにレジスタを割り当てるのですか、どのようにロックを実装するのですか?これは実際にはコンパイラとOSライターの間で考えることが難しい問題です)

リエントラント2つのスレッドが同時に同じメソッドを呼び出すときに悪いことが起こることは証明されません。メソッドが他の共有リソースにアクセスして更新しないと悪いことは起こりません。

関連する問題