如何缓存实时数据?

时间:2011-05-10 18:38:24

标签: vb.net .net-4.0 mschart dde

  • 我正在使用Windows窗体应用程序(.NET 4.0)。
  • 我的表单包含使用VS2010中包含的Microsoft图表控件的“快速线”图表。
  • 该图表充满了大约20,000个数据点。
  • 我的应用程序然后开始通过DDE(动态数据交换)实时从服务器接收市场数据,并将其添加到图表中。

注意: 我无法控制服务器,所以即使它是一种过时的技术,我也只能处理DDE。 VS不再支持DDE,所以我使用的Ndde库就像魅力一样。

首先我们连接到服务器,创建一个advise循环,然后订阅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()中的值对任何进一步没有帮助)

我在网上找到的唯一帮助就是有人提到你应该将传入的数据放在缓存队列中的旧帖子,一次从现金中释放一个新的数据值(每次图表完成工作时)。 / p>

我的问题是你会怎么做?

欢迎提出其他建议!

2 个答案:

答案 0 :(得分: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 它还有令人遗憾的线程亲和性要求,这使得处理垃圾收集器成为一种真正的痛苦。

答案 1 :(得分:0)

变得真实;)DDE很慢,图形很慢。不要在同一个线程中执行它们。

试试:

  • 创建第二个处理DDE的线程,对项目进行排队。
  • 图表线程然后提取更新并绘制它们。

现在,重点是:

  • 只允许ui线程修改图表控件。是的,太糟糕了。不,不可谈判。 - 自从时间开始以来的旧UI规则。
  • 线程需要锁定;)