2

UI のフリーズを解決する方法について質問があります。

はじめに: 現在、特定のアナライザー ツール用に OPC ベースのオンライン アラーム リーダーをプログラミングしています。このツールは、Excel シートからデータを受け取り、ルール ベースとトポロジ モデルを使用してこのデータを分析し、結果を TreeViewItems で表示します。私の仕事は、Excel シート リーダーをリアルタイム アラーム リーダーに置き換えることです。これで、ソフトウェアをサーバーに接続し、新しいアラームが作成されるたびにデータ パッケージを受信できるようになりました。

問題: 新しいデータをメイン クラスに転送し、そこからアナライザー クラスに転送するための私の解決策は、データをリストに保存し、それらを EventArgs に追加して、イベントを発生させることです。メイン クラスの処理メソッドは、このデータを受け取り、アナライザーの新しいタスク (Task>) を開始し、その結果をメイン スレッドに返します。この構成により、UI から計算プロセスが分離されているはずです。分析プロセスには、サンプル データで約 1.3 秒かかります。新しいデータは、平均して 2 秒ごとに到着します。同時に 2 秒が最高のリフレッシュ時間です。

添付は、処理メソッドのコード スニペットです。

    Task<List<Analyser.ALARM_GROUP>> analysertask = Task.Factory.StartNew<List<Analyser.ALARM_GROUP>>(
                    ()=>
                        {
                            /*if the alarmlist is emty, set the new alarms as alarmlist, 
                             * else add the new alarms to the present list*/
                            if (AlarmList1.Count == 0)
                                AlarmList1 = e.CurrentAlarms;

                            else listModifier.mergeList(e.CurrentAlarms, AlarmList1);

                            /*Start the analysis process in a seperate task and return the Alarm_Group-List*/
                            return Analyser1.startAnalysis(PlantModelReader1, AlarmlogReader1, RuleBaseLoader1, AlarmList1); 
                        });

                Cursor = Cursors.Wait;
                List<Analyser.ALARM_GROUP> alarmGroupList = analysertask.Result;

                showAlarmLog(alarmGroupList);

                Cursor = Cursors.Arrow;

残念ながら、プロセスの分析を開始しても UI は動かず、2 秒ごとに新しいスレッドを開始するという私の概念 (新しいアラームの平均出現時間) が妥当な概念であるかどうかさえわかりません。問題は showAlarmLog 内にあると思いますが、それは多くのコードです。必要に応じて、このコードも投稿します。

この問題に関する提案があれば感謝します。「あなたのコンセプトはくだらないです。このアイデアを試してください: ...」でも知っておくとよいでしょう。

よろしくラリモウ

4

1 に答える 1

4

問題は、この呼び出し:

List<Analyser.ALARM_GROUP> alarmGroupList = analysertask.Result;

バックグラウンド タスクが完了するまで UI スレッドをブロックします。

これを処理する方法は、結果を待つ代わりに継続タスクを使用することです。

Task<List<Analyser.ALARM_GROUP>> analysertask = Task.Factory.StartNew<List<Analyser.ALARM_GROUP>>(
    ()=> {
        // Keep existing code
        return Analyser1.startAnalysis(PlantModelReader1, AlarmlogReader1, RuleBaseLoader1, AlarmList1); 
         });

// Make a continuation here...
analysertask.ContinueWith( t =>
    {
        Cursor = Cursors.Wait;
        List<Analyser.ALARM_GROUP> alarmGroupList = t.Result;
        showAlarmLog(alarmGroupList);
        Cursor = Cursors.Arrow;
    }, TaskScheduler.FromCurrentSynchronizationContext());

これを継続としてスケジュールすると、最初のタスクが完了したときに実行されます。を使用TaskScheduler.FromCurrentSynchronizationContextすることで、実行時にこれを UI スレッドにマーシャリングします。


これは、.NET 4.5/C# 5 ではるかに簡単になることに注意してください。C# 5 では、次のように記述できます。

var analysertask = Task.Run(
    ()=> {
        // Keep existing code
        return Analyser1.startAnalysis(PlantModelReader1, AlarmlogReader1, RuleBaseLoader1, AlarmList1); 
         });

Cursor = Cursors.Wait;
List<Analyser.ALARM_GROUP> alarmGroupList = await analysertask;
showAlarmLog(alarmGroupList);
Cursor = Cursors.Arrow;

asyncただし、これにはメソッド自体に new キーワードでフラグを付ける必要があります。

于 2012-06-15T16:56:56.730 に答える