我正在研究开发一种应用程序,该应用程序将以每秒约2000行(帧)的速度处理来自线扫描相机的数据。对于这个实时应用程序,我觉得C / C ++是要走的路。 (这是我的感觉,其他人会同意托管代码不适合这项任务。)
但是,我已经完成了非常小MFC或任何其他C ++ GUI。不过,我真的很想做C#GUI。
所以我很自然地用C / C ++编写数据密集型代码,用C#编写GUI。 GUI将用于设置/校准/在线监控(并可能通过UDP输出数据,因为它在C#中更容易。
首先,我想看看是否有人同意这是可行的方法。根据我的编程经验(擅长低级C算法和高级C#GUI设计),感觉恰到好处。
其次,我不确定正确的方法。我只是在VS2005中汇总了一个解决方案,它从C#应用程序中调用了一些(extern“C”)DLL函数。为了确保我能做到这一点,我写了DLL中的一些全局变量,并从中读取:
test.h
int globaldata;
extern "C" __declspec(dllexport) void set(int);
extern "C" __declspec(dllexport) int get();
TEST.CPP
extern int data=0;
__declspec(dllexport) void set(int num) {
data = num;
}
__declspec(dllexport) int get() {
return data;
}
test.cs中
[DllImport("test")]
private static extern void set(int num);
[DllImport("test")]
private static extern int get();
致电get()
和set()
正常工作(get()
会返回我传递给set()
的号码。)
现在,我知道您也可以导出C ++类,但它是否必须进行管理?这是如何运作的?我是以正确的方式来做这件事吗?
感谢您的帮助!
*** EDIT ***
首先,谢谢你到目前为止您的精彩答案!我总是对Stack Overflow印象深刻......
我想我应该注意的一件事,不一定是原始速度(这可以是原型和基准)。让我更关心的一件事是垃圾收集器的非确定性行为。该应用程序在执行垃圾收集时 不能容忍500ms的延迟。
我完全用于编码并在纯C#中尝试此操作,但如果我提前知道GC和任何其他非确定性.NET行为(?)会导致问题,我认为我的时间会更好用C / C ++编写代码并找出最佳的C#接口。
答案 0 :(得分:31)
答案 1 :(得分:16)
在我看来,你的解决方案是合理的:
你的解决方案,如果你还没有想到它,被称为“混合模式”,这基本上意味着你在同一个项目中结合托管(C#)和非托管(C / C ++)代码,它通常是让VS项目正常运行有点麻烦(LNK2020错误......)..但是当你找到合适的设置时它应该可以正常工作。
唯一不好的是,混合模式程序集必须以完全信任方式运行,如果可以,那么我想你知道该怎么做。
您可能想要了解的另一件事是名为SWIG的开源项目。 SWIG接受你的C / C ++代码并用它创建一个.NET程序集,我在我的TM++开源项目中自己使用它。有关SWIG http://www.swig.org/的更多信息,请参见此处。
答案 2 :(得分:6)
对于实时应用程序:我推荐使用C ++,根据使用的框架,你将更灵活地进行内存管理,更快,甚至是多平台...!
关于框架和GUI,我建议您查看Qt。 Qt是一个很好的C ++软件开发框架。
我想这是你问题的解决方案!
答案 3 :(得分:5)
您需要做的第一件事是测试您的假设。你的性能限制是什么?您期望托管应用程序的硬件类型是什么?在C#中编写一个小程序来处理核心问题并测量其运行速度。
只有掌握了事实,才能决定是否在托管解决方案上使用C / C ++。
与其他评论过的人一起,我怀疑C#/托管解决方案会做得很好,特别是如果你使用.NET Parallel Extensions。
如果你最终进入C / C ++路由,那么有两个选项可以互换,即pInvoke和COM interop。我不相信有一种直接从.NET访问非托管C ++类的简洁方法;为此,您必须考虑implementing a managed/unmanaged C++ assembly。
答案 4 :(得分:4)
虽然用CCD相机代替线扫描相机,但我的公司做的非常相似。我们使用C#进行GUI,网络通信,高级“管道”和低级算法的C ++ / CLI。它运作得很好。你永远无法编写一个真正的实时系统,保证在Windows上有最长的响应时间,但根据我的经验,GC将是你在这里遇到的最少的问题。首先,GC只在你分配内存时运行; C / C ++中的malloc / new也是如此,它们也需要时间(想想内存碎片)。根据我们已经完成的测量,一个完整的GC需要10-50ms,并且在此期间不会成功停止其他线程(除非他们尝试分配管理内存,我认为),这对我们来说没问题。但是我不确定这些数字是否可以推广到任何类型的应用程序,你可能应该自己进行分析以确定。
如果您害怕GUI可能会破坏您的实时约束,您可以考虑将实际的图像处理放入一个单独的进程中,并使用管道/套接字与GUI进行通信。或者至少在设计系统时要记住这个选项,所以如果你真的遇到了不可预见的性能问题,那么你将它作为最坏的选择。
您的第二个问题是您是否应该使用C ++或C#作为实际算法。就个人而言,当我编写复杂的图像处理算法时,我觉得在C ++中更容易理解。我认为该语言更适合于该任务,并且C / C ++的数字库比C#要多得多。但这可能是个人偏好的问题。从性能的角度来看,C ++的优势在于C ++内联器优于.NET JIT内联器(即它可以内联更多的小函数调用)。
如果您选择使用C ++,我建议使用C ++ / CLI:这样,您可以编写编译为托管代码的C ++类。 C ++优化器将优化它们,只有.NET JIT才能完成本机代码的最后一个编译步骤。最大的优点是您可以直接从C ++ / CLI访问.NET类,并且可以轻松地在C ++ / CLI中创建可以从C#访问的托管类。您不需要在围栅的两侧编写包装代码。 (C ++ / CLI有点笨重,因为它包含用于托管和非托管编程的语言结构,但如果您已经熟悉非托管C ++和C#,那么理解它可能不会有任何问题。)
答案 5 :(得分:2)
对于C ++,您使用C ++ / CLI - 实际上并没有那么糟糕。它比旧的托管扩展程序好很多。
评论表现。这真的取决于。你的C ++代码和C#代码之间会有多少来回?你是否有一个后台线程用C ++收集数据并定期将其发送到C#代码?如果您要与设备连接,是否会使用串口,USB,某些API?
答案 6 :(得分:1)
我同意Mitch 100%。
如果在调查他的资源之后,你仍然觉得你需要使用一些非托管代码,你可以用C ++编写一个“业务”层(或者在这种情况下,实际上是一个功能层)并用C#编写你的UI。使用COM Interop从C#/托管代码调用非托管代码。
但是,我的感觉是你不需要这样做。
答案 7 :(得分:0)
您选择的语言不会对性能产生太大影响(比如说您可以将速度提高5/10%)。 最重要的是您将使用的算法,如何处理数据,分析您的应用程序等......(性能可能会以10倍的比例变化)。
答案 8 :(得分:0)
我用C ++ .NET完成了它
由于C ++ .NET和C#都是托管的,我不明白为什么不能这样做。关键是你将如何做到这一点。
我的扫描仪最高可达3000行/秒,但关键策略是一次显示32行的块。我没有很难的实时要求,所以有时我可能会有点落后。如果实时对您非常重要,您应该考虑切换平台。
有一个名为“InTime OS”的实时Windows解决方案,但使用它真的很痛苦。
您可以拥有的另一种方法是将硬实时分离到单独的dll或库中,让C#以自己的速度显示它的内容。实际上,用户永远无法判断您的界面是否具有2000 fps或500 fps
答案 9 :(得分:0)
我有本机C / C ++和C#极低延迟系统的经验。
在C / C ++中,确定性malloc方法中80%的处理器时间丢失,但本机代码比msil代码快10倍
在C#内存分配更快,因为它是一个异步过程
您的选择必须通过以下比率来完成:处理时间/ malloc编号
如此粒度!!!
C / C ++的解决方案是在内存中预分配所有缓冲区(如果需要,使用预取L2 / L3缓存)
C#的解决方案是最小化P-Invoke转换机制
祝贺你的项目,保罗
答案 10 :(得分:0)
前端wpf和c ++后端(pinvoke)很快,但是当您在线程上执行GUI工作时,您的GUI线程也不会被您的后台代码阻止。当你这样做时,你的程序看起来会更快,更轻。
答案 11 :(得分:-3)
为何选择Windows? 与任何unixes相比,它具有可怕的内存性能和更糟糕的网络。专门捕获线传感器意味着您需要一个设备来处理原始输入。考虑首先使用正确的操作系统,这将大大降低您必须处理的其他压力(我对线扫描仪技术非常熟悉)。