2014年08月24日

C#で並行処理

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

■問題 (出題者:sumim さん)
数値(たとえば1から10)と、アルファベット(たとえばAからJまで)を順に出力する別々のループ処理を並行に実行させ、共通の出力先に出力する極力シンプルなコードを書いてください。
念のため、実行後、出力先に数値とアルファベットが混ざって出力されている(たとえば、数値がすべて出力されてからアルファベットが続く…というふうになっていない)ことを確認してください。混ざってさえいれば、それぞれ1文字ずつ交互である必要はありませんし、もちろん交互でも構いません。
出力先や出力方法は自由です。標準出力、テキストファイル、コンテナオブジェクト(配列、リスト、コレクション)など使いやすいもので構いません。
例として Squeak Smalltalk でのコードと結果を示します。シンプルなコードなので Smalltalk に馴染みがない人も、おおよその内容は掴めると思います。
| out |
out := OrderedCollection new.

[(1 to: 10) do: [:each | out add: each. Processor yield]] fork.
[($A to: $J) do: [:each | out add: each. Processor yield]] forkAndWait.

^out asArray  "=> #(1 $A 2 $B 3 $C 4 $D 5 $E 6 $F 7 $G 8 $H 9 $I 10 $J) "


もちろん可能であれば、疑似である必要はありません。^^;


出力先はいちばん簡単と思われる標準出力としました。
まずは、Threadクラスを使ったコード。

using System;
using System.Linq;
using System.Threading;
using System.Collections;
using System.Threading.Tasks;

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

        // Threadを使った例
        private static void ParallelTest() {
            Thread th1 = new Thread(PrintSeq);
            Thread th2 = new Thread(PrintSeq);
            th1.Start("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
            th2.Start("abcdefghijklmnopqrstuvwxyz");
            th1.Join();
            th2.Join();
        }

        // 引き数 obj は、IEnumerableを実装している必要がある。引き数の値を順に出力する。
        // PrintSeqが直ぐに終わらないように、途中でウエイトしている。
        private static void PrintSeq(object obj) {
            foreach (var x in (IEnumerable)obj) {
                Console.Write(x.ToString());
                Thread.Sleep(2);
            }
        }
    }
}

いちおう、Taskクラスを使ったコードも書いてみた。これくらい単純な問題ならば、Taskクラス使うのも悪くない。

using System;
using System.Linq;
using System.Threading;
using System.Collections;
using System.Threading.Tasks;

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

        static void ParallelTest() {
            var task1 = Task.Factory.StartNew(PrintSeq, "ABCDEFGHIJKLMNOPQRSTUVWXY");
            var task2 = Task.Factory.StartNew(PrintSeq, "abcdefghijklmnopqrstuvwxyz");
            task1.Wait();
            task2.Wait();
        }

        // 引き数 obj は、IEnumerableを実装している必要がある。引き数の値を順に出力する。
        // PrintSeqが直ぐに終わらないように、途中でウエイトしている。
        private static void PrintSeq(object obj) {
            foreach (var x in (IEnumerable)obj) {
                Console.Write(x.ToString());
                Thread.Sleep(2);
            }
        }
   }
}


 

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

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