我正在尝试使用FTDI的D3XX.NET从USB端口收集数据。收集数据,然后将其发送到快速傅立叶变换以绘制频谱。即使您错过了一些数据,它也可以正常工作。你不知道但是,如果您随后希望将此数据发送到音频输出组件,则会注意到数据丢失。这就是我的问题所在。 收集数据,然后将其发送到音频设备。所有数据包都在所需的时间范围内达到目标。但是,音频正在丢弃显示的数据。这是音频输出中正弦波的图片:
您可以看到开始时缺少一些数据,并且似乎在结束时缺少了整个周期。这只是一个例子,它一直在变化。有时似乎数据不存在。 我已经遍及整个处理链,并且我很确定声音的数据包正在制作。 从那以后,我就使用了JetBrains性能分析器。我发现了以下内容:ReadPipe方法耗时8.5ms,这恰好是您期望读取的时间。到目前为止,一切都很好。 ReadPipe命令完成后,您需要0.5毫秒来执行另一个ReadPipe,否则您将丢失一些数据。查看探查器输出,我看到以下内容:
ReadPipe花费8.5毫秒,然后有一个条目用于垃圾回收,平均花费1.6毫秒。如果确实确实发生了这种情况,那么我已经丢失了一些数据。
下面是代码:它是后台工作人员:
private void CollectData(object sender, DoWorkEventArgs e)
{
while (keepGoing)
{
ftStatus = d3xxDevice.ReadPipe(0x84, iqBuffer, 65536, ref bytesTransferred); //read IQ data - will get 1024 pairs - 2 bytes per value
_waitForData.Set();
}
}
waithandle向另一个线程表示数据可用。 那么GC是造成数据丢失的原因吗?如果是这样,我该如何避免呢? 谢谢!
答案 0 :(得分:4)
如果可以确认内存还没耗尽,可以尝试将GCSettings.LatencyMode
设置为GCLatencyMode.SustainedLowLatency
。除非您的内存不足,否则这将防止发生某些阻塞垃圾收集。请查看docs on latency modes,以了解更多详细信息和限制。
如果对于您的用例而言,垃圾回收仍然无法解决问题,并且您正在使用.NET 4.6或更高版本,则可以尝试调用GC.TryStartNoGCRegion。此方法将尝试保留足够的内存以分配指定数量的内存,并阻止GC,直到用尽保留空间为止。如果您的内存使用情况相当一致,则可以传递足够大的值来容纳应用程序的使用情况,但是并不能保证调用会成功。
如果您使用的旧版.NET不支持这两个版本,则可能不走运。如果这是一个GUI应用程序(由事件处理程序判断,它看起来像),则您没有足够的控制分配。
要考虑的另一件事是,对于不能容忍中断的应用程序,C#并不是真正的正确工具。如果您熟悉编写本机代码,则可以在非托管线程上执行对时间敏感的工作。据我所知,这是唯一可靠的解决方案,尤其是当您的应用程序要在最终用户计算机上运行时。
答案 1 :(得分:2)
您需要对垃圾收集器更加友好,并且分配的资源不要太多。
简而言之,如果您的GC
阻塞了线程,那么您就会遇到垃圾问题。 GC将暂停所有线程以进行清理,并且除了更好地管理所创建的垃圾之外,您别无他法。
如果有数组,请不要持续创建它们,而要重用它们(依此类推)。使用较轻的结构,使用允许您减少诸如Span<T>
和Memory<T>
之类的分配的工具。如果您的代码过多awaits
,请考虑使用较少的async
,并且不要将它们放在循环中。通过ref
并使用ref locals等,如果可以的话,也应远离大型非托管数据块。
另外,在无关紧要的任何停机时间调用GC.Collect
可能会有所帮助,尽管更好的设计可能会更有利。