我的两位.(哦,一个警告,我之所以提到ATL COM,是因为您使用MFC时所造成的性能损失不值得.我记得,当通过MFC调用时,速度要慢两个数量级.MFC COM Object与ATL上的接口相对应,并且不能满足我们的需求;另一方面,ATL的速度比直接在C ++中直接调用等效函数要慢一些.即使我们正在收集和移动大量的超声数据,也没有发现瓶颈.哦,我发现了: http://msdn.microsoft.com/en-us/library/ms973839.aspx ".NET应用程序中的性能提示和技巧".我发现这句话很有趣:要加快过渡时间,请尝试尽可能使用P/Invoke.开销仅需31条指令,再加上成本如果需要数据封送,则为封送,否则为8.通讯互操作要昂贵得多,最多需要65条指令.示例部分的标题:进行大量调用",用于字符串迭代的循环使用",正在寻找异步IO机会".所引用的快速内存库中的一些摘要:在 MemoryArray.cs 中 公共MemoryArray(int parElementCount,int parElementSize_bytes){描述符=新的MemoryArrayDescriptor(元帅.AllocHGlobal(parElementCount * parElementSize_bytes),parElementSize_bytes,parElementCount);}受保护的重写void OnDispose(){如果(Descriptor.StartPointer!= IntPtr.Zero)Marshal.FreeHGlobal(Descriptor.StartPointer);base.OnDispose();}//如果您要顺序访问,则实际上仅应将其用于随机访问项目//使用枚举器,该枚举器通过数组描述符的TryMoveNext调用使用指针数学.////我还没有弄清楚它到底会去哪里,但是你也可以做类似的事情//具有一个在此处更新的MemoryArrayItem成员,而不是每个成员都创建一个新成员//时间;这会破坏试图保留对该项目的引用的任何内容,因为//它将不再是不变的.////可以通过类似调用的方法来补救,该调用可以返回该项目的新副本(如果有的话)//要保留.我肯定需要看到我需要性能提升和//在我与用户对此的期望相抵触之前,这已经足够有意义了.公共MemoryArrayItem此[int i]{得到{返回新的MemoryArrayItem(this,Descriptor.GetElementPointer(i),Descriptor.ElementSize_bytes);}}//您也可以进行多维索引;为此,您必须以某种方式传递尺寸//构造函数并存储它们.////为此您可以做各种事情;取各种切片,等等,在之间进行切换//倒数第一/倒数第一/自定义维度排序等,但在示例中我没有解决.////如果您不需要在此处进行错误检查,则始终可以执行以下操作:公共MemoryArrayItem this [int x,int y]{得到{如果(myDimensions == null)抛出新的ArrayTypeMismatchException(试图在不调用SetDimensions()的情况下索引二维数组");如果(myDimensions.Length!= 2)抛出新的ArrayTypeMismatchException(当前设置的尺寸不提供二维数组.[尺寸:" + myDimensions.Length +]"));int RowSize_bytes = myDimensions [0] * Descriptor.ElementSize_bytes;返回新的MemoryArrayItem(this,Descriptor.StartPointer +(y * RowSize_bytes)+ x * Descriptor.ElementSize_bytes,Descriptor.ElementSize_bytes);}}公共无效SetDimensions(int [] parDimensions){如果(parDimensions.Length< = 0)抛出新的Exception(无法将数组设置为零维.");为(int i = 0; i< parDimensions.Length; ++ i)如果(parDimensions [i]< = 0)抛出新的ArgumentOutOfRangeException(无法将索引" + i.ToString()+的维设置为" + parDimensions [i] +.");myDimensions = new int [parDimensions.Length];parDimensions.CopyTo(myDimensions,0);}private int [] myDimensions = null; 来自 MemoryArrayEnumerator.cs 公共类MemoryArrayEnumerator:IEnumerator< MemoryArrayItem>{//处理主数组的引用计数私有AutoReference< MemoryArray>myArray;私有MemoryArray数组{get {return myArray;}}私人IntPtr myCurrentPosition = IntPtr.Zero;公共MemoryArrayEnumerator(MemoryArray parArray){myArray = AutoReference< MemoryArray> .CreateFromExisting(parArray);}//---------------------------------------------------------------------------------------------------------------#region IEnumerator< MemoryArrayItem>执行//---------------------------------------------------------------------------------------------------------------公共MemoryArrayItem当前{得到{如果(Array.Descriptor.CheckPointer(myCurrentPosition))返回新的MemoryArrayItem(myArray,myCurrentPosition,Array.Descriptor.ElementSize_bytes);别的抛出新的IndexOutOfRangeException(枚举器错误:Current()超出范围");}}公共无效Dispose(){myArray.Dispose();}对象System.Collections.IEnumerator.Current{得到{抛出新的NotImplementedException();}}公共布尔MoveNext(){bool RetVal = true;如果(myCurrentPosition == IntPtr.Zero)myCurrentPosition = Array.Descriptor.StartPointer;别的RetVal = Array.Descriptor.TryMoveNext(ref myCurrentPosition);返回RetVal;}公共无效Reset(){myCurrentPosition = IntPtr.Zero;}//---------------------------------------------------------------------------------------------------------------#endregion IEnumerator< MemoryArrayItem>执行//--------------------------------------------------------------------------------------------------------------- In .NET there are several places when you must leave managed code and enter the realm of unmanaged a.k.a. native code. To name a few:extern dll functionsCOM invocationThere are always comments about overhead that jump from one side to another causes, and my question here is if anybody MEASURED exact overhead that is happening, and can explain how it can be calculated. For example, maybe byte[] can be converted to IntPtr or even to byte* in .NET and help marshaller save some CPU cycles. 解决方案 [I see I didn't really answer the question about how you would measure; the best way to measure is just with some instrumentation, either with the instrumentation classes (see: http://msdn.microsoft.com/en-us/library/aa645516(v=vs.71).aspx) or even with something as simple as placing in some timers around whatever calls you're interested in. So, in the crudest form, when we were trying to find the performance hit taken, for instance, in our call between C# and ATL COM, we would just place timers around an empty function call we would start a timer, run in a tight loop between C# and the empty ATL COM function, do enough loops that we were able to get reasonably consistent answers between runs, and then do the exact same thing in C++. Then, the difference between those two numbers is the overhead for making the call across that boundary.]I don't really have any hard numbers, but I can answer from previous experience that as long as you use things in an efficient way, C# performs with very little, if any, overhead beyond what one might expect in C++, depending on the exact nature of what you are trying to do.I worked on several applications that collected very large amounts ultrasonic data through very high frequency (100MHz-3GHz A/D boards) and by doing certain things, as you suggest, (things like byte[] arrays allocated in managed code and then locked down as pointers and passed as buffers for the data; transferring large amounts of data and processing it for imaging various parts).Way back when, we communicated with C++ code to VB6, and we would wrap the C++ in ATL Simple COM objects, and pass pointers back and forth when needed for data and imaging. We practiced similar techniques much later with C# in VS.NET 2003. Also, I have written a library for a question here that allows for massive unmanaged data storage that can provide support for very large arrays and array operations, as well as even a lot of LINQ-type functionality! Using array fields instead of massive number of objects . (note: there are some issues with the reference counting that were in the latest version, and I have not yet tracked down.)Also, I have done some interfacing using ATL COM with the FFTW library in order to perform high-performance DSP to good effect, although that library is not quite ready for primetime, it was the basis of the spike solution I created for the link above, and the spike gave me most of the information I was looking for to complete my much more full-blown unmanaged memory allocator and fast-array processing supporting both externally allocated as well as unmanaged allocations from the unmanaged heap, which will eventually replace the processing that currently exists in the FFTW C# library.So, the point is, I believe the performance penalty is very overblown, especially with the processing power we have these days. In fact, you can get very good performance if you just take care to avoid some of the pitfalls (like calling lots of little cross-boundary functions instead of passing buffers, or multiple allocations of strings and such) using C# by itself. But when it comes to high-speed processing, C# still can fit the bill for all of the scenarios I've mentioned. Does it take a little forethought, yes, sometimes. But the advantages gained in development speed, maintainability, and understandability, the time I spent figuring out how to get the performance I need has always been far less than the amount of time it would have taken to develop primarily or completely in C++.My two bits. (Oh, one caveat, I mention ATL COM specifically because the performance hit you took when using MFC was not worth it. As I recall it, it was about two orders of magnitude slower when calling out via an MFC COM Object versus the interface on the ATL one, and did not meet our needs. ATL on the other hand was only a smidge slower than calling the equivalent function directly in C++. Sorry, I do not recall any particular numbers offhand, other than that even with the large amounts of ultrasonic data we were collecting and moving around, we did not find it a bottleneck.)Oh, I found this: http://msdn.microsoft.com/en-us/library/ms973839.aspx "Performance Tips and Tricks in .NET Applications". I found this quote very interesting: To speed up transition time, try to make use of P/Invoke when you can. The overhead is as little as 31 instructions plus the cost of marshalling if data marshalling is required, and only 8 otherwise. COM interop is much more expensive, taking upwards of 65 instructions.Sample section titles: "Make Chunky Calls", "Use For Loops for String Iteration", "Be on the Lookout for Asynchronous IO Opportunities".Some snippets from the referenced Fast Memory Library:in MemoryArray.cs public MemoryArray(int parElementCount, int parElementSize_bytes) { Descriptor = new MemoryArrayDescriptor ( Marshal.AllocHGlobal(parElementCount * parElementSize_bytes), parElementSize_bytes, parElementCount ); } protected override void OnDispose() { if (Descriptor.StartPointer != IntPtr.Zero) Marshal.FreeHGlobal(Descriptor.StartPointer); base.OnDispose(); } // this really should only be used for random access to the items, if you want sequential access // use the enumerator which uses pointer math via the array descriptor's TryMoveNext call. // // i haven't figured out exactly where it would go, but you could also do something like // having a member MemoryArrayItem that gets updated here rather than creating a new one each // time; that would break anything that was trying to hold on to a reference to the item because // it will no longer be immutable. // // that could be remedied by something like a call that would return a new copy of the item if it // was to be held onto. i would definitely need to see that i needed the performance boost and // that it was significant enough before i would contradict the users expectations on that one. public MemoryArrayItem this[int i] { get { return new MemoryArrayItem(this, Descriptor.GetElementPointer(i), Descriptor.ElementSize_bytes); } } // you could also do multiple dimension indexing; to do so you would have to pass in dimensions somehow in // the constructor and store them. // // there's all sorts of stuff you could do with this; take various slices, etc, do switching between // last-to-first/first-to-last/custom dimension ordering, etc, but i didn't tackle that for the example. // // if you don't need to error check here then just you could always do something like: public MemoryArrayItem this[int x, int y] { get { if (myDimensions == null) throw new ArrayTypeMismatchException("attempted to index two dimensional array without calling SetDimensions()"); if (myDimensions.Length != 2) throw new ArrayTypeMismatchException("currently set dimensions do not provide a two dimensional array. [dimension: " + myDimensions.Length + "]"); int RowSize_bytes = myDimensions[0] * Descriptor.ElementSize_bytes; return new MemoryArrayItem(this, Descriptor.StartPointer + (y * RowSize_bytes) + x * Descriptor.ElementSize_bytes, Descriptor.ElementSize_bytes); } } public void SetDimensions(int[] parDimensions) { if (parDimensions.Length <= 0) throw new Exception("unable to set array to dimension of zero."); for (int i = 0; i < parDimensions.Length; ++i) if (parDimensions[i] <= 0) throw new ArgumentOutOfRangeException("unable to set dimension at index " + i.ToString() + " to " + parDimensions[i] + "."); myDimensions = new int[parDimensions.Length]; parDimensions.CopyTo(myDimensions, 0); } private int[] myDimensions = null;from MemoryArrayEnumerator.cspublic class MemoryArrayEnumerator : IEnumerator<MemoryArrayItem>{ // handles reference counting for the main array private AutoReference<MemoryArray> myArray; private MemoryArray Array { get { return myArray; } } private IntPtr myCurrentPosition = IntPtr.Zero; public MemoryArrayEnumerator(MemoryArray parArray) { myArray = AutoReference<MemoryArray>.CreateFromExisting(parArray); } //--------------------------------------------------------------------------------------------------------------- #region IEnumerator<MemoryArrayItem> implementation //--------------------------------------------------------------------------------------------------------------- public MemoryArrayItem Current { get { if (Array.Descriptor.CheckPointer(myCurrentPosition)) return new MemoryArrayItem(myArray, myCurrentPosition, Array.Descriptor.ElementSize_bytes); else throw new IndexOutOfRangeException("Enumerator Error: Current() was out of range"); } } public void Dispose() { myArray.Dispose(); } object System.Collections.IEnumerator.Current { get { throw new NotImplementedException(); } } public bool MoveNext() { bool RetVal = true; if (myCurrentPosition == IntPtr.Zero) myCurrentPosition = Array.Descriptor.StartPointer; else RetVal = Array.Descriptor.TryMoveNext(ref myCurrentPosition); return RetVal; } public void Reset() { myCurrentPosition = IntPtr.Zero; } //--------------------------------------------------------------------------------------------------------------- #endregion IEnumerator<MemoryArrayItem> implementation //--------------------------------------------------------------------------------------------------------------- 这篇关于托管到非托管开销的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!