作为数组间接c ++返回数据的更快方法

时间:2015-10-19 16:07:17

标签: c# c++ arrays performance interop

这是一个非常干净和漂亮的解决方案,从非托管C ++代码marsahall结构数组。 在简单性方面它是最完美的解决方案,我花了一些时间来理解这个概念,所以在几行代码中,你可以看到C#Main(),我有一个填充的数组结构准备好被收获' ..

typedef struct {
int Id;
BSTR StrVal;
}Package;

extern "C" __declspec(dllexport) void dodata(int requestedLength,int StringSize, Package **Packs){

    int count;
    count=0;
    *Packs = (Package*)LocalAlloc(0, requestedLength * sizeof(Package));
    Package *Cur = *Packs;
    while(count!= requestedLength)
    {
        Cur[count].StrVal = NULL;
        Cur[count].Id = count;
        Cur[count].StrVal=SysAllocString(L"abcdefghij");
        Cur[count].StrVal[StringSize-1]=count+'0';

    ++count;

    }

}

C#

[DllImport(@"ExportStructArr.dll", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void dodata(int requestedLength, int StringSize, out IntPtr csPkPtr);


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct csPk
{
    public int V;
    [MarshalAsAttribute(UnmanagedType.BStr, SizeConst = 10)]
    public string testStr;
}

static void Main(string[] args){

    int ArrL = 16000;
    csPk[] Cpk = new csPk[ArrL];
    IntPtr CpkPtr = IntPtr.Zero;
    int szPk = Marshal.SizeOf(typeof(csPk));
    dodata(ArrL, 10, out CpkPtr);
}

现在我所要做的就是:

        for (int i = 0; i < Cpk.Length; i++)
        {
            Cpk[i] = (csPk)Marshal.PtrToStructure(new IntPtr(CpkPtr.ToInt32() + (szPk * i)), typeof(csPk));
        }
如你所见,解决方案非常简单 问题是对数据使用不安全或任何类型的转换,甚至可以使用字节......

如何优化它以更好地返回数据?

编辑:

链接我试图从SO中的其他答案中学习:

还尝试了谷歌:wikipediaa github post by stephentoub

1 个答案:

答案 0 :(得分:1)

这是一个完整的超快速解决方案来填充对象列表,我尽我所能 我很乐意收到意见和建议。

<强> C ++

typedef struct _DataPacket
{
    BSTR buffer;
    UINT size;
} DataPacket;

extern "C" __declspec(dllexport)  void GetPacksUnsafe( int size, DataPacket** DpArray )
{
    int szr = size;int count=0;
    *DpArray = (DataPacket*)CoTaskMemAlloc( szr * sizeof( DataPacket ));

    if ( DpArray != NULL )
    {
        DataPacket* CurPack = *DpArray;

        for ( int i = 0; i < szr; i++, CurPack++ )
        {
            CurPack->size = i;
            CurPack->buffer = SysAllocString(L"SomeText00");
            CurPack->buffer[9]=i+'0';   

        }
    }
}

<强> C#

    [DllImport(@"ExportStructArr.dll", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
    public static extern void GetPacksUnsafe(int size, PackU** outPackUArr);

    [StructLayout(LayoutKind.Sequential)]
    public unsafe struct PackU
    {
        public char* StrVal;
        public int IntVal;
    }


    public static unsafe List<PackU> PopulateLstPackU(int ArrL)
    {
        PackU* PackUArrOut;
        List<PackU> RtLstPackU = new List<PackU>(ArrL);
        GetPacksUnsafe(ArrL, &PackUArrOut);
        PackU* CurrentPack = PackUArrOut;
        for (int i = 0; i < ArrL; i++, CurrentPack++)
        {
            RtLstPackU.Add(new PackU(){ StrVal = CurrentPack->StrVal, IntVal=CurrentPack->IntVal});
        }
        Marshal.FreeCoTaskMem((IntPtr)PackUArrOut);

        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine("{0}", new string(RtLstPackU[i].StrVal));
        }
        return RtLstPackU;
    }

使用代码非常简单

    static unsafe void Main(string[] args)
    {
        int ArrL = 100000;
        List<PackU> LstPackU;
        LstPackU = PopulateLstPackU(ArrL);
    }

你有一个像子弹一样快的自定义数据列表..

修改

使用指针而不是字符串:

typedef struct _DataPackCharPnt
{
    char* buffer;
    UINT IntVal;
} DataPackCharPnt;


extern "C" __declspec(dllexport)  void GetPacksPnt( int size, DataPackCharPnt** DpArrPnt )
{

    int count = 0;
    int TmpStrSize = 10;
    *DpArrPnt = (DataPackCharPnt*)CoTaskMemAlloc( size * sizeof( DataPackCharPnt ));
    DataPackCharPnt* CurPackPnt = *DpArrPnt;
    char dummyStringDataObject[]= "abcdefgHi";
    for ( int i = 0; i < size; i++,CurPackPnt++ )
    {

        dummyStringDataObject[9] = i+'0';
        CurPackPnt->IntVal=i;
        CurPackPnt->buffer = (char*)malloc(sizeof(char)*TmpStrSize);
        strcpy(CurPackPnt->buffer, dummyStringDataObject);

    }
}

将填充100k元素的时间从11毫秒减少到7毫秒

是否可以省略创建buffer的任何部分?

  • dummyStringDataObject的职责是模拟工作,比如获取一个文件名然后用它的值设置缓冲区,所以除了这个额外的时间,这是这个函数的全部目的,返回一些未知的值和字符串的长度......

你能进一步优化吗?