2015年03月08日

C#でリングノードベンチマーク

   このエントリーをはてなブックマークに追加 Clip to Evernote
どう書く?orgに感謝を込めて」シリーズ その75

■問題 (出題者:tsuwabukiさん)
N個のノードを作り、1番目のノードに送られたメッセージは2番目のノードに、
2番目のノードに送られたメッセージは3番目のノードに、・・・、
N番目のノードに送られたメッセージは1番目のノードに送られるようにリングを形成し、
そのリング上を一つのメッセージがM回まわるのにかかる時間を計測してください。


M回の情報は、Nodeに持たせるべきなのか? Messageに持たせるべきなのか?すこし悩みましたが、 ここでは Node に持たせてみました。
なお、普通にメソッド呼び出しで、メッセージ送信を書くと、最後のメッセージを送った後に、処理はメソッドの呼び出し元に順に逆戻りしていくことになります。
これだととても無駄なことしているように思えてしまいます。それと、n,mの数が多いと、Stack Overflow の可能性もあります。
そのため、メソッド呼び出しでメッセージ送信するのではなく、Taskクラスを使い、タスクを非同期に起動する方法にしてみました。

でも、Waitの方法がちょっと気に入らないです。
ちなみに、最後までメッセージが渡ったら、そのメッセージをコンソールに出力させています。

あなたならどう書く?

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;

namespace Doukaku.Org {
    class Program {
        static void Main(string[] args) {
            RingNodeBench(300, 50);
            Console.ReadLine();
        }

        static void RingNodeBench(int n, int m) {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            // n個のノードを作成し、リングを形成。
            Node node1 = new Node(m);
            Node curr = node1;
            for (int i = 1; i < n; i++) {
                curr.Next = new Node(m);
                curr = curr.Next;
            }
            curr.Next = node1;

            // 一つ目のノードにメッセージを送信
            Message msg = new Message { Text = "メッセージ"  };

            node1.Post(msg);
            Node.Wait();

            sw.Stop();

            Console.WriteLine(sw.ElapsedMilliseconds);
        }
  

    }

    class Message {
        public string Text { get; set; }
    }

    class Node {
         private static AutoResetEvent _autoResetEvent = new AutoResetEvent(false);

        public static void Wait() {
            _autoResetEvent.WaitOne();
        }

        private int _count;
        public Node(int count) {
            _count = count;
        }
        public Node Next { get; set; }

        public void Post(Message message) {
            if (_count-- <= 0) {
                _autoResetEvent.Set();
                Console.WriteLine(message.Text);
                return;
            }
            Task.Factory.StartNew(() => this.Next.Post(message));
        }
    }
 }


 

この記事へのトラックバックURL

http://trackback.blogsys.jp/livedoor/gushwell/52408064