ビジーウェイトを避け、代わりに。などのタイマーを使用する必要がありますTask.Delay
。
これを行うための1つの可能な方法は、C#4.5の新しい非同期機能を利用することです。
async void converse() {
txtInput.Text = "hi\n";
await Task.Delay(2000);
txtInput.Append("hello\n");
await Task.Delay(4000);
txtInput.Append("awesome\n");
await Task.Delay(1000);
txtInput.Append("nice\n");
}
非同期構文を使用することで、他のコードとインターリーブされたコードを実行するようにマシンに指示します。これにより、たとえば、その間に画面の更新を実行できます。自動的に同じSynchronizationContextに戻るため、GUIスレッドを開始してから、そのまま使用できます。そのスレッドだけがテキストボックスを変更する可能性があるため、これは重要です。
次のようにこれを実行する理由を要約すると、次のようになります。
- エネルギーを浪費するものを待つのに忙しいCPUを占有することを避けます。
- GUIスレッドのブロックを回避して、更新が時間どおりに表示されるようにします(CPUの占有とは異なり、たとえばThread.Sleepとは異なります)。
- 非同期機能がスレッドのスケジューリングを行うので、スレッドのスケジューリングについて特に心配する必要はありません。
.NET 2.0をサポートする必要がある場合は、Windowsフォームを確認することをお勧めしますTimer
。つまり、これにより、遅延後に発生するフック可能なイベントハンドラーが公開されます。ただし、MSDNページの例が示すように、使用はそれほど簡単ではなく、より多くの手動オーケストレーションが必要になります。
さらに、スレッドを使用することもできます。txtInput.Append
その場合、スレッドの安全性を確保する責任があります。GUIスレッド以外のスレッドで実行することはできません。
void startConversation() {
(new Thread(converse) {IsBackground = true}).Start();
}
void converse() { //called a different thread
UI(() => txtInput.Text = "hi\n");
Thread.Sleep(2000);
UI(() => txtInput.Append("hello\n"));
Thread.Sleep(4000);
UI(() => txtInput.Append("awesome\n"));
Thread.Sleep(1000);
UI(() => txtInput.Append("nice\n"));
}
void UI(Action action) { this.BeginInvoke(action); }
このモデルは、非同期モデルとほぼ同じくらい単純です。2つの落とし穴は、ビジーウェイトを回避する必要があること(Thread.Sleepを使用)と、BeginInvoke
UIに影響を与えるすべてのコードを適切に使用することを確認する必要があることです。おそらく少しでも速いでしょうasync
。ただし、スレッドにはかなり大きなオーバーヘッド(主にメモリの観点から)があるため、このソリューションは大量の遅延インタラクションに拡張できません。
概要
- 可能であれば使用
async
してください。
Timer
または、面倒なWindowsフォームを使用します。
- または、バックグラウンドスレッドを使用しますが、スケーリングの問題とビジーウェイトに注意してください。