【发布时间】:2011-06-28 06:57:07
【问题描述】:
我最近一直在尝试使用R.NET 让 R 与 .NET 和 C# 对话。到目前为止一切都很顺利,但我遇到了一个我似乎无法解决的问题。
我对简单的基本命令没有任何问题。我做了一个简单的计算器,以及将数据导入数据网格的东西。但现在我不断收到以下错误:
对“R.NET!RDotNet.Internals.blah3::Invoke”类型的垃圾收集委托进行了回调。这可能会导致应用程序崩溃, 损坏和数据丢失。将委托传递给非托管代码时,它们必须 由托管应用程序保持活动状态,直到确保它们永远不会被调用。
当我尝试重复导入一个文本文件时,它开始了,只是为了测试一些东西。我以各种方式查找了此错误 - 经过数小时的网页搜索,似乎有多种原因导致此类错误。随着时间的推移,我一直在将我的代码剥离到越来越简单的任务中,以试图消除可能性。我现在有了这个:
public Form1()
{
InitializeComponent();
REngine.SetDllDirectory(@"C:\Program Files\R\R-2.13.0\bin\i386");
REngine.CreateInstance("RDotNet");
using (REngine currentEngine = REngine.GetInstanceFromID("RDotNet"))
{
for (int i = 0; i < 1000; ++i)
{
currentEngine.EagerEvaluate("test <- " + i.ToString());
NumericVector returned = currentEngine.GetSymbol("test").AsNumeric();
textBox1.Text += returned[0];
}
}
}
它所做的只是增加 textBox1.Text 中的计数。我一直在做一个测试,按下按钮来增加值,但这让我的手指在一段时间后感到疼痛!它通常可以在抛出上述错误之前管理大量印刷机。
起初这段代码似乎没问题 - 所以我认为我一直在做的其他事情是问题的原因,以及上面引用的错误的原因。所以这就是我放入 for 循环的原因。循环可以运行数百次而没有问题,但随后就会出现错误。
现在,我确实读到这种错误可以由垃圾收集器调用,以摆脱我一直在使用的实例。我已经尝试了我阅读的各种建议,因为我最好理解它们。这些包括使用 GC.KeepAlive() (不走运),以及在一个单独的类中创建一个无法摆脱的私有字段。遗憾的是,这也不起作用。
还有什么我可以尝试的吗?我对 C# 非常非常陌生,因此我将不胜感激有关如何使其正常工作的任何指示。我非常认为,我在建议的方法上缺乏成功要么与(1)我自己在实施标准修复时的错误(这似乎很可能)有关,要么与(2)我没有的与 R.NET 相关的怪癖有关不明白。
任何帮助将不胜感激!
【问题讨论】:
-
您将 GC.KeepAlive 调用究竟放在哪里?这是正确的解决方法,但必须在最后一次需要之后 - 方法结束是最简单的。
-
我不知道你的具体问题,但它让我想起了我最近反复尝试写入文本文件的类似情况。它大部分时间都有效,除了在我的下一次写入操作发生之前操作系统尚未完成关闭文件连接的那些零星情况。我知道你只是从你的文件中读取,但教训可能仍然存在:尝试以最小化文件操作次数的方式编写代码。换句话说,读取文件并将其存储在内存中,直到完成循环。
-
我没有看到您将委托传递给非托管代码。你能添加你的那部分代码吗?
-
@Marc Gravell - 我在各种奇怪而美妙的地方调用了 KeepAlive,但它们似乎都不起作用。例如,我在上面 using 块的末尾尝试了它,但没有运气。我再次尝试删除 using 块并再次将 KeepAlive 放在方法的末尾,但它仍然抛出错误。
-
@agent-j 据我所知,我并没有明确地对代表做任何事情。我假设我正在使用的库内部发生了一些事情,那就是调用一个。我浏览了对象浏览器和在线指南,但遗憾的是,这个库的文档非常薄。