2011-05-10 95 views
2
  • 我工作的一個Windows窗體應用程序(.NET 4.0)。
  • 我的表單包含使用VS2010中包含的Microsoft圖表控件的「Fast Line」圖表。
  • 該圖表充滿大約20,000個數據點。
  • 我的應用程序,然後開始從通過DDE(動態數據交換),實時接收服務器市場數據並將其添加到圖表。

注:我沒有對服務器無法控制,所以我必須處理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中並使其自動失效(刷新)。而服務器通常非常快速地發送數據值(例如中間5ms)。所以我嘗試了以下內容:

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

因此暫停應用程序可以給時間圖表添加新點前完成其工作,你猜怎麼着?在拋出異常之前,應用程序現在可以運行數分鐘。 (改變Sleep()中的值並沒有幫助)然而,

我唯一可以在網上找到的幫助是有人提到你應該將傳入的數據放入緩存隊列中,有一個新的數據值一次從現金中釋放(每次圖表完成工作時)。

我的問題是你會怎麼做呢?

歡迎您提出其他建議!

+3

任何機會,從一個非UI線程更新圖表數據採集是嗎? – Gabe 2011-05-10 18:40:19

+0

這聽起來像是一個線程問題 - 有人試圖在枚舉時修改集合。 – rsbarro 2011-05-10 18:47:17

+0

OnAdvise是一個事件委託功能嗎?嘗試調用方法AddY而不是執行。 (或者更好的辦法是查看InvokeRequired的值,假設這個值是真的,我認爲這是真的,如果沒有調用它(同步地將數據傳遞給另一個線程),你不能安全地調用它。但是,需要做的事情是將結果中的附加點保留下來,並在停止迭代數據點之後添加它們。在迭代過程中,集合不會被改變,而下一個傳遞將會有更新的數據。 – 2011-05-10 18:48:01

回答

2

這是最有可能發生企圖從比UI線程以外的線程修改UI元素的問題。

你現在所編碼的DdeClient.Advise事件處理程序正在由庫管理的工作線程的執行方式。看,DDE糟透了,因爲它吸收它有這些要求,它必須在消息泵的線程上運行。 爲了使庫與除了Windows窗體以外的其他類型的應用程序兼容,我編碼它的方式是它將創建一個帶有消息循環的專用線程,並將所有操作編組到默認情況下。

但是,您可以通過在DdeClient構造函數中手動指定ISynchronizeInvoke實例來覆蓋此行爲。然後該庫將使用任何線程爲其所有的DDE操作託管ISynchronizeInvoke實例。所有FormControl實例都實現了ISynchronizeInvoke,因此很容易告訴庫使用主UI線程。

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

如果你告訴庫,然後用你的Form實例Advise事件處理程序將承載相同的線程上執行的Form; UI線程。

順便說一句,我意識到你無法控制服務器,但我至少會開始與軟件供應商交談,以使用更現代(而不是20年)的機制來進行進程間通信。


它也有這使得處理垃圾收集一個真正的痛苦線程相似的不幸需求。

+0

很棒的回答。感謝Brian的洞察力。哦,我不能同意DDE。我們在發言時正在向供應商發送電子郵件。 – Marven 2011-05-10 20:00:17

0

Get real;)DDE速度慢,圖形速度慢。不要在同一個線程中執行它們。

試一下:

  • 創建處理DDE第二個線程,隊列中的項目。
  • 圖表線程然後拉動更新並繪製它們。

現在,來了一點:

  • 只有UI線程被允許修改圖表控件。是的,很爛。不,不可談判。 - 自創建以來的舊UI規則。
  • 線程需要鎖定;)