2
  • 私は、Windows フォーム アプリケーション (.NET 4.0) に取り組んでいます。
  • 私のフォームには、VS2010 に含まれている Microsoft チャート コントロールを使用した「Fast Line」チャートが含まれています。
  • グラフは約 20,000 のデータポイントでいっぱいになります。
  • 私のアプリケーションは、DDE (Dynamic Data Exchange) を介してリアルタイムでサーバーから市場データの受信を開始し、それをチャートに追加します。

注:私はサーバーを制御できないため、時代遅れのテクノロジであるにもかかわらず、DDE のみを処理する必要があります。VS は DDE をサポートしなくなったので、魅力的に機能するNddeライブラリを使用しています。

最初にサーバーに接続し、アドバイス ループを作成してから、OnAdvise イベントにサブスクライブして、新しいデータの通知を受け取ります。

Dim client As DdeClient = New DdeClient("ServerApplication", "Bid")

Private Sub StartDDE()
    client.Connect()
    client.StartAdvise("EURUSD", 1, True, 60000)
    AddHandler client.Advise, AddressOf OnAdvise
End Sub

これで、イベント内にチャートを更新するコマンドを配置できます。

Private Sub OnAdvise(ByVal sender As Object, ByVal args As DdeAdviseEventArgs)
    Dim myPrice As Double = args.Text
    Chart1.Series("Bid").Points.AddY(myPrice)
End Sub

あなたはアイデアを得る。

問題:

これは、チャートがクラッシュして例外「コレクションが変更されました。列挙操作が実行されない可能性があります」をスローするまで、数秒間正常に機能します。

特定のケースでこの原因が何であるかを調査するのに多くの時間を費やしましたが、チャートが処理できるよりも速くデータを受信して​​いることが原因であるという結論に達しました。すでに大量のデータがロードされており、受信したデータを新しい DataPoint に追加し、それ自体を無効化 (更新) するには、一定の時間 (1 秒未満) が必要です。一方、サーバーは多くの場合、データ値を非常に迅速に送信します (たとえば、間に 5 ミリ秒)。だから私は次のことを試しました:

System.Threading.Thread.Sleep(800)
Chart1.Series("Bid").Points.AddY(myPrice)

したがって、アプリケーションを一時停止して、新しいポイントを追加する前にチャートが作業を完了する時間を与えます。アプリケーションは、例外をスローする前に数分間動作するようになりました。(ただし、Sleep() の値を変更しても、それ以上は役に立ちません)

私がオンラインで見つけることができる唯一の助けは、一度に 1 つの新しいデータ値をキャッシュから解放して (チャートの動作が終了するたびに)、受信データをキャッシュ キューに入れる必要があると述べている誰かの古い投稿です。

私の質問は、これをどのように行うかです。

他の提案は大歓迎です!

4

2 に答える 2

2

これは、UI スレッド以外のスレッドから UI 要素を変更しようとしたことが原因である可能性が高いです。

コーディングした方法ではDdeClient.Advise、ライブラリによって管理されるワーカー スレッドでイベント ハンドラーが実行されます。ほら、DDEは最悪です。それが最悪なので、メッセージポンプを備えたスレッドで実行する必要があるというこれらの要件があります。1ライブラリを Windows フォーム以外の他のタイプのアプリケーションと互換性を持たせるために、メッセージ ループを持つ専用スレッドを作成し、デフォルトですべての操作をそのスレッドにマーシャリングするようにコーディングしました。

ただし、コンストラクターISynchronizeInvokeでインスタンスを手動で指定することにより、この動作をオーバーライドできます。DdeClient次に、ライブラリは、ISynchronizeInvokeすべての DDE 操作でインスタンスをホストしているスレッドを使用します。すべてFormControlインスタンスが実装されISynchronizeInvokeているため、メインの UI スレッドを使用するようにライブラリに指示するのは簡単です。

Dim client As DdeClient = New DdeClient("ServerApplication", "Bid", yourForm)

Formインスタンスを使用するようにライブラリに指示すると、Adviseイベント ハンドラはそれをホストしている同じスレッドで実行されFormます。UI スレッド。

ところで、あなたがサーバーを制御できないことは承知していますが、少なくともソフトウェアのベンダーと話し合って、プロセス間通信を行うためのより最新の (20 年前ではない) メカニズムを使用するようにします。


1また、ガベージ コレクタの処理を非常に困難にするスレッド アフィニティの不運な要件もあります。

于 2011-05-10T18:59:46.103 に答える
0

本当のことを理解してください ;) DDE は遅く、グラフィックスも遅いです。それらを同じスレッドで実行しないでください。

それを試してください:

  • DDE を処理する 2 番目のスレッドを作成し、アイテムをキューに入れます。
  • 次に、チャート スレッドが更新をプルして描画します。

さて、ポイントは次のとおりです。

  • チャート コントロールを変更できるのは、ui スレッドだけです。はい、最悪です。いいえ、交渉できません。- 黎明期からの古い UI ルール。
  • スレッドにはロックが必要です ;)
于 2011-05-10T18:59:55.207 に答える