C#禁用USB ReadPipe的垃圾收集

C#禁用USB ReadPipe的垃圾收集,c#,garbage-collection,usb,real-time,C#,Garbage Collection,Usb,Real Time,我正试图从FTDI使用D3XX.NET从USB端口收集数据。收集数据,然后发送到快速傅里叶变换以绘制光谱。即使丢失了一些数据,这也可以正常工作。你不知道。但是,如果您希望将此数据发送到音频输出组件,则会发现数据丢失。这就是我的问题所在。 收集数据,然后发送到音频设备。所有数据包都在所需的时间范围内完成。但是,音频正在删除它显示的数据。以下是音频输出时正弦波的图像: 您可以看到,一些数据在开始时丢失,而在接近结束时,整个周期似乎都丢失了。这只是一个例子,它一直在变化。有时,数据似乎并不存在。 我

我正试图从FTDI使用D3XX.NET从USB端口收集数据。收集数据,然后发送到快速傅里叶变换以绘制光谱。即使丢失了一些数据,这也可以正常工作。你不知道。但是,如果您希望将此数据发送到音频输出组件,则会发现数据丢失。这就是我的问题所在。 收集数据,然后发送到音频设备。所有数据包都在所需的时间范围内完成。但是,音频正在删除它显示的数据。以下是音频输出时正弦波的图像:

您可以看到,一些数据在开始时丢失,而在接近结束时,整个周期似乎都丢失了。这只是一个例子,它一直在变化。有时,数据似乎并不存在。 我已经完成了整个处理过程,我非常确定声音的数据包正在制作中。 此后,我使用了JetBrains性能分析器。我发现如下:ReadPipe方法需要8.5ms,这正是您所期望的读取时间。到现在为止,一直都还不错。ReadPipe命令完成后,您有0.5毫秒的时间执行另一个ReadPipe,否则会丢失一些数据。查看探查器输出,我看到以下内容:

ReadPipe需要8.5ms,然后有一个垃圾收集条目,平均需要1.6ms。如果这种情况确实偶尔发生,那么我丢失了一些数据

下面是代码:它是一个后台工作人员:

    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是数据丢失的原因吗?如果是这样,我该如何避免这种情况?
谢谢

您需要对垃圾收集器更友好,并且不要分配太多

简而言之,如果您的
GC
正在暂停线程,那么您就有了垃圾问题。GC将暂停所有线程以进行清理,除了更好地管理您创建的垃圾之外,您真的无能为力

如果您有阵列,不要不断地创建它们,而是重用它们(等等)。使用较轻的结构,使用允许减少分配的工具,如
Span
内存
。如果使用代码<>代码>异步y>代码,请考虑使用< <代码>等待> <代码>,不要把它们放在循环中。通过
ref
并使用ref局部变量等,如果可以,也要远离大型非托管数据块


此外,在不重要的任何停机时间调用
GC.Collect
可能会有好处,但更好的设计可能会更有益。

如果您能确认内存没有用完,您可以尝试将
GCSettings.LatencyMode
设置为
GCLatencyMode.SustainedLowLatency
。这将防止发生某些阻塞垃圾收集,除非内存不足。有关更多详细信息和限制,请查看

如果垃圾收集对于您的用例来说仍然太具破坏性,并且您正在使用.NET 4.6或更高版本,那么您可以尝试调用。此方法将尝试保留足够的内存以分配到指定的数量,并阻止GC,直到您用完保留为止。如果您的内存使用相当一致,那么您可能可以传递一个足够大的值来适应应用程序的使用,但不能保证调用会成功

如果您使用的是旧版本的.NET,它不支持这两个选项,那么您可能就倒霉了。如果这是一个GUI应用程序(根据事件处理程序判断,它看起来很像),那么您对分配没有足够的控制


另一个需要考虑的问题是,C语言并不是真正不能容忍破坏的应用程序的正确工具。如果您熟悉编写本机代码,则可以在未管理的线程上执行时间敏感的工作;据我所知,这是唯一可靠的解决方案,尤其是当您的应用程序将在最终用户机器上运行时。

代码中有成千上万行。对于这种特殊情况,这是不可能的。那么,探查器是否指示此线程在GC期间阻塞?如果是这样的话,如何预防呢?@tom确实,它似乎在说垃圾收集被阻塞了150毫秒,这在音频领域是一个很长的时间。也许你可以做一些技巧来提示垃圾收集,也许其他人可以在这里插话并给出一些建议。这就是89个电话的总时间149毫秒。在发生读取管道的4207次期间,调用了89次。每次调用时,它的总长度为1.4ms。这一定是问题的根源。@Tom查看此链接,没有看到您的解决方案和分析结果,这很难说,但这可能会给oyu一个更好的指示,如果这是一个问题。谢谢。我正在使用.NET4.0。我尝试将GC更改为lowLatency,还尝试了库提供的ReadPipeAsync方法,但没有任何区别。现在,D3XX.NET库只是一堆非托管代码的C#包装器。那么,将我的线程创建为au非托管线程并使用其中的代码是什么想法呢?是的,您必须创建自己的非托管库,其中包含一个函数,该函数生成一个后台线程来执行您需要的任何操作,然后P/Invoke进入其中。非托管线程在垃圾收集期间不会暂停。不过,这相当复杂。我发布了一篇关于如何做到这一点的后续文章