yield returnでマイクロスレッド。んで、かえるうたの輪唱。
コルーチンでマイクロスレッドなクラスを作成します。
using System; using System.Collections.Generic; using System.Collections; using System.Threading; namespace WindowsApplication1 { /// <summary> /// MicroThread /// </summary> public class MicroThread { private List<CoRoutine> threads = new List<CoRoutine>(); public IEnumerable NextThread() { while (true) { var allDone = true; foreach (CoRoutine thread in threads) { if (thread.IsDone) { allDone = false; yield return thread.Process(); } } if (allDone) yield break; } } public void Add(IEnumerable en) { threads.Add(new CoRoutine(en)); } public void Execute(){ new Thread(new ThreadStart(CreateThread)).Start(); } private void CreateThread(){ foreach (var e in this.NextThread()) ; } /// <summary> /// CoRoutine /// </summary> private class CoRoutine { /// <summary> /// コンストラクタ /// </summary> /// <param name="en"></param> public CoRoutine(IEnumerable en) { this.en = en.GetEnumerator(); } private IEnumerator en { get; set; } public bool IsDone { get{ return en.MoveNext(); } } private object Current { get { return en.Current; } } public object Process() { if (IsDone) return en.Current; return null; } } } }
んで、試しに使ってみます。
「かえるのうた」の輪唱で並列処理っぽい雰囲気を出してみる。
using System; using System.Collections.Generic; using System.Collections; using System.Windows.Forms; namespace WindowsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); //Control.CheckForIllegalCrossThreadCalls = false; } private void btnKaeru_Click(object sender, EventArgs e) { this.textBox1.Clear(); this.textBox2.Clear(); this.textBox3.Clear(); var mt = new MicroThread(); mt.Add(kaeru1(x => textBox1.AppendText(x))); mt.Add(kaeru2(x => textBox2.AppendText(x))); mt.Add(kaeru3(x => textBox3.AppendText(x))); mt.Execute(); } private object AppendText(Action<string> proc,string s) { if (this.InvokeRequired) { this.Invoke(proc, new object[]{s}); return null; } proc.Invoke(s); return null; } private IEnumerable kaeru1(Action<string> f) { yield return AppendText(f, "かえるのうたが\n"); yield return AppendText(f, "きこえてくるよ\n"); yield return AppendText(f, "グワッグワッグワッグワッ\n"); yield return AppendText(f, "ゲロゲロゲロゲロ\n"); yield return AppendText(f, "グワッグワッグワッ\n"); yield break; } private IEnumerable kaeru2(Action<string> f) { yield return AppendText(f, "\n"); yield return AppendText(f, "かえるのうたが\n"); yield return AppendText(f, "きこえてくるよ\n"); yield return AppendText(f, "グワッグワッグワッグワッ\n"); yield return AppendText(f, "ゲロゲロゲロゲロ\n"); yield return AppendText(f, "グワッグワッグワッ\n"); yield break; } private IEnumerable kaeru3(Action<string> f) { yield return AppendText(f, "\n"); yield return AppendText(f, "\n"); yield return AppendText(f, "かえるのうたが\n"); yield return AppendText(f, "きこえてくるよ\n"); yield return AppendText(f, "グワッグワッグワッグワッ\n"); yield return AppendText(f, "ゲロゲロゲロゲロ\n"); yield return AppendText(f, "グワッグワッグワッ\n"); yield break; } } }
おー、いい具合にコルーチンがマイクロスレッドっぽく振舞ってますね。
それはそうと、yield return null;ってやるのはどうも気持ち悪いです。
C#4.0では、yield return null;って書かなくてもよいようにしてもらえると嬉しい。