0

私は少し問題に遭遇しました。2つのスレッドがあります。1つはループを実行し、毎回GUIのスレッドに数値を返したり送信したりする必要があります。このために、BackGroundWorkerReportProgressを使用します。

そのようなことを言ってみましょう:

私はBackGroundWorkerを持っており、 0から何でもカウントする単純なループを実行します(DoWork)。ループへのすべてのエントリは、ReportProgressイベントを使用してカウンターをGUIのスレッドに送信し、カウンターの値を出力します。

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        int count = 0;
        BackgroundWorker Worker = (BackgroundWorker)sender;

        while (count < 10000000)
        {
            Worker.ReportProgress(count);
            count++;
        }
    }

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        txt.Text = e.ProgressPercentage.ToString();
    }

現在、この操作によりGUIがフリーズします。

ReportProgressがBackGroundWorkerを作成したスレッドでProgressChangeハンドラーを呼び出していることを理解しているので、ループが非常に高速に実行されているため、GUIのスレッドが必要に応じて値を出力できません。

GUIをフリーズせずにそのようなタスクを実行するにはどうすればよいですか?

ディスパッチャーについて聞いたことがありますが、それが何に使用されるのかよくわかりません。

4

3 に答える 3

3

問題は、何かが変更されるたびに reportProgress を呼び出していることです。進捗状況を報告する必要がある場合にのみ呼び出す必要があります。MSDN http://msdn.microsoft.com/en-us/library/ka89zff4.aspxを参照してください。dowork を次のように変更します。

 while (count < 10000000)
    {
        if ((count % 1000) == 0)
            Worker.ReportProgress(count);
        count++;
    }

これにより、1000 個のアイテムが処理されるたびに ReportProgress が呼び出されるため、GUI スレッドに不要な負荷がかかることはありません。

于 2012-11-04T20:16:47.273 に答える
1

コード例は、GUI が更新通知メッセージを処理できるよりもはるかに速い速度で GUI を更新しようとしているため、GUI Windows メッセージ キューがガンジであふれ、他のメッセージの処理を妨げています - GUI フリーズ。

GUI 以外のスレッドで高レートの操作の進行状況を監視することは、ポーリングが優れたソリューションである数少ないケースの 1 つです。Forms.Timer イベントを使用して、おそらくスレッドのメソッドによって返される「currentProgress」値を読み取って表示します。500 ミリ秒は妥当なタイマー値です。人間のユーザーは、それよりもはるかに速い速度で編集/テキスト ボックス内の整数値の変化に追いつくことはできません。

「理想的には」、currentProgress 値の読み取り/書き込みは、おそらくアトミックな操作でロックする必要がありますが、500 ミリ秒ごとに int を読み取るだけの場合は、おそらくそれは必要ないでしょう。スレッドは、進行状況カウントがレジスターに継続的にキャッシュされる可能性が非常に低いことを意味します。

于 2012-11-05T10:09:49.933 に答える
0

GUID をフリーズせずにそのようなタスクを実行するにはどうすればよいですか? :

とにかく、ディスパッチャを使用すると、WPFを使用していると思い込まされました。

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    int count = 0;
    BackgroundWorker Worker = (BackgroundWorker)sender;

    while (count < 10000000)
    {
        Worker.ReportProgress(count);
        count++;
    }
}

void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    Dispatcher.BeginInvoke((Action)(() => { txt.Text = e.ProgressPercentage.ToString(); }));
}

Dispatcher.BeginInvoke を呼び出すと、指定された Action が実際に UI スレッドで実行され、UI 要素にアクセスする UI スレッド以外のスレッドの原因に対して例外がスローされないようにします。

また、タスクを使用する代替手段として、これを試すこともできます。

于 2012-11-04T20:19:04.137 に答える