2

私は C# で現実的なコンソール タイプのゲームを作成しようとしています。そのために必要なことは、次のようなテキストを追加することです。

こんにちは
こんにちは
素晴らしい
素敵です

しかし、一度にすべてを実行する代わりに、これを実行したい:

こんにちは
(2 秒間の休止)
こんにちは
(4 秒間の休止)
素晴らしい
(1 秒間の休止)
いいね

私はこれを試しました:

delegate void _pause(int time);
    void pause(int time)
    {
        if (txtInput.Text != "")
        {
            txtInput.Clear();
        }

        Stopwatch s = new Stopwatch();
        s.Start();
        while (s.Elapsed < TimeSpan.FromSeconds(time))
        {
        }
        s.Stop();
        return;
    }

そして、このように呼び出すことができますInvoke(new _pause(pause),3);が、それは基本的にスレッドをフリーズさせます! とにかく一度に貼り付けます。貼り付けのモンタージュの少し前です。

説明したようなスムーズな遅延タイプのシステムを作成するにはどうすればよいですか?

4

2 に答える 2

3

ビジーウェイトを避け、代わりに。などのタイマーを使用する必要があります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を使用)と、BeginInvokeUIに影響を与えるすべてのコードを適切に使用することを確認する必要があることです。おそらく少しでも速いでしょうasync。ただし、スレッドにはかなり大きなオーバーヘッド(主にメモリの観点から)があるため、このソリューションは大量の遅延インタラクションに拡張できません。

概要

  • 可能であれば使用asyncしてください。
  • Timerまたは、面倒なWindowsフォームを使用します。
  • または、バックグラウンドスレッドを使用しますが、スケーリングの問題とビジーウェイトに注意してください。
于 2013-02-21T09:31:32.457 に答える
0

この方法でこの問題を修正しました: GUI をロックせずにメソッドの実行を一時停止します。C#

別のスレッドで一時停止を実行することで簡単に修正できるため、UI をロックしません。みんなの助けに感謝します!

于 2013-02-21T10:00:27.017 に答える