COM服务项目中数据块(数组)的高效传输方式

发布时间 2023-11-07 10:32:02作者: 永恒月华

1. 问题背景

《C#程序与COM服务程序传递数组和字符串的方式》一文中,我提供了数组的传递方式,是通过 atlsafe.h 中 CComSafeArray 模板类来实现的,但是在实际开发过程中发现,直接使用其自身提供的随机数据访问函数进行数据操作速度较慢,在大量传输数据时运行时间不可接受,所以本文记录一种高效传输方式。

 1 STDMETHODIMP_(HRESULT __stdcall) CSimple::GetSourceDataInByte(SAFEARRAY** arr)
 2 {
 3     CComSafeArray<BYTE>* sfArrObj = new CComSafeArray<BYTE>;
 4     // 这里 _sourceData 是 CSimple 中的源数据成员,类型为 void*
 5     BYTE* srcData = static_cast<BYTE*>(_sourceData);
 6     // 调用 Create() 为 sfArrObj 内数据分配内存空间;_srcDataLen 是源数据个数,类型为 ULONG
 7     sfArrObj->Create(_srcDataLen);
 8     for (ULONG i = 0; i < _srcDataLen; ++i) {
 9         sfArrObj->SetAt(i, *(srcData + i));
10     }
11     *arr = sfArrObj->Detach();
12     delete sfArrObj;
13     sfArrObj = NULL;
14     return S_OK;
15 }

这个方法实现中,使用循环赋值的方式对 sfArrObj 中的数据块赋值,实测上亿数据量时运行时间在20秒以上。


 

2. 解决办法

考虑通过内存拷贝方式进行传输,需要用到标准库中的 memcpy() 函数。

 1 STDMETHODIMP_(HRESULT __stdcall) CSimple::GetSourceDataInByte(SAFEARRAY** arr)
 2 {
 3     CComSafeArray<BYTE>* sfArrObj = new CComSafeArray<BYTE>;
 4     sfArrObj->Create(_srcDataLen);
 5     SAFEARRAY* safeArr = sfArrObj->Detach();
 6     memcpy(_safeArr->pvData, _sourceData, _srcDataLen * sizeof(BYTE));
 7     sfArrObj->Attach(safeArr);
 8     *arr = sfArrObj->Detach();
 9     delete sfArrObj;
10     sfArrObj = NULL;
11     safeArr = NULL;
12     return S_OK;
13 }

通过这种方式传输亿级数据仅需3秒左右。