2

アウトプロセス COM サーバーを実装する必要があり、すべての COM インターフェイスがオートメーション互換であるとします。プロキシとスタブの組み合わせを作成して登録するか、タイプ ライブラリを作成して登録し、オートメーション マーシャラーに依存することができます。

私は、2 つのアプローチのすべての保守面を十分に認識しています。この質問は、実行時のパフォーマンスのみに関するものです。

ハードデータが見つかりません-次のような主張のみ

  1. 「オートメーション マーシャラーはジェネリックなので遅い」というのは、オートメーションと互換性のある型がいくつかあるだけで、それらを切り替えるのはそれほど難しくないので、すぐには信じられません。

  2. 「オートメーションマーシャラーはタイプライブラリをロードする必要があります」これは公正なポイントですが、これは1回だけ実行する必要があり、その後10万回のCOM呼び出しが発生した場合、その1回限りのオーバーヘッドはあまり気にしません

プロキシ/スタブ マーシャリングまたはタイプライブラリ マーシャリングが長期的に高速な測定データはありますか?

4

1 に答える 1

1

Essential Comの Don Box (p. 228) と彼の Microsoft Systems Journal 記事 (1999 年 1 月)によると、プロキシが作成されると、PSOAInterface のパフォーマンスは /Oicf プロキシ/スタブ ライブラリのパフォーマンスと同じになるはずです。

しかし、Windows 8.1 の時点では、PSOAInterface プロキシの作成は最適ではない可能性があります。Don Box は上記の記事で、combase!CreateProxyFromTypeInfo とタイプ ライブラリ マーシャラーがキャッシュを実行すると主張しています。ただし、私のテストでは、すべてのインターフェイスを解放するたびに、タイプ ライブラリがファイルから再読み込みされます。これは、IGlobalInterfaceTable を広範囲に使用する UIAutomation ライブラリの重大な問題であり、余分なシステム コールが大量に発生します。

これが私のテストです。1 つのアパートメントがコクラスをインスタンス化し、別のアパートメントがそれをプロキシに 10000 回アンマーシャリングします。PSOAInterface を使用する場合、約 5 秒かかります。代わりに MIDL プロキシ/スタブを作成して登録すると、約 100 ミリ秒しかかかりません。

#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <comdef.h>

// RemoteProxyFactory32 from oleacc.dll {53362c64-a296-4f2d-a2f8-fd984d08340b}
static IID CLSID_RemoteProxyFactory32 = GUID{ 0x53362c64, 0xa296, 0x4f2d, { 0xa2, 0xf8, 0xfd, 0x98, 0x4d, 0x08, 0x34, 0x0b } };
// IRemoteProxyFactory from oleacc.dll {8628f27d-64a2-4ed6-906b-e6155314c16a}
static IID IID_IRemoteProxyFactory = GUID{ 0x8628f27d, 0x64a2, 0x4ed6, { 0x90, 0x6b, 0xe6, 0x15, 0x53, 0x14, 0xc1, 0x6a } };

struct register_interface_thread {
    HANDLE hInterfaceRegistered;
    DWORD dwCookie;
    HANDLE hShouldClose;
};
DWORD WINAPI RegisterInterfaceThread(_In_  LPVOID lpParameter) {
    struct register_interface_thread& state = *(struct register_interface_thread*)(lpParameter);
    HRESULT hr;
    if (FAILED(hr = CoInitializeEx(NULL, COINIT_MULTITHREADED))) {
        fprintf(stderr, "Error CoInitializeEx: 0x%08x\n", hr);
    }
    else {
        IUnknown *pv;
        if (FAILED(hr = CoCreateInstance(CLSID_RemoteProxyFactory32, NULL, CLSCTX_LOCAL_SERVER, IID_IRemoteProxyFactory, (LPVOID*)&pv))) {
            fprintf(stderr, "CocCreateInstance(RemoteProxyFactory32 of oleacc.dll) failed with hresult 0x%x\n", hr);
        }
        else {
            IGlobalInterfaceTable *pIGlobalInterfaceTable;
            if (FAILED(hr = CoCreateInstance
                (
                CLSID_StdGlobalInterfaceTable,
                NULL,
                CLSCTX_INPROC_SERVER,
                IID_IGlobalInterfaceTable,
                (void **)&pIGlobalInterfaceTable
                ))) {
                fprintf(stderr, "CocCreateInstance(StdGlobalInterfaceTable) failed with hresult 0x%x\n", hr);
            }
            else {
                DWORD dwCookie;
                if (FAILED(hr = pIGlobalInterfaceTable->RegisterInterfaceInGlobal(pv, IID_IRemoteProxyFactory, &dwCookie))) {
                    fprintf(stderr, "RegisterInterfaceInGlobal failed with hresult 0x%x\n", hr);
                }
                else {
                    fprintf(stdout, "Successfully registered interface; cookie=0x%x\n", dwCookie);
                    state.dwCookie = dwCookie;
                    if (!SetEvent(state.hInterfaceRegistered)) {
                        DWORD err = GetLastError();
                        fprintf(stderr, "Error SetEvent(hInterfaceRegistered): 0x%x\n", err);
                    }
                    else {
                        DWORD waitResult;
                        if (WAIT_OBJECT_0 != (waitResult = WaitForSingleObject(state.hShouldClose, INFINITE))) {
                            DWORD err = GetLastError();
                            fprintf(stderr, "Error WaitForSingleObject: returned 0x%x; error=0x%08x\n", waitResult, err);
                            hr = err;
                        }
                        else {
                            fprintf(stdout, "Successfully joined thread; dwCookie=0x%x\n", state.dwCookie);
                        }
                    }
                }
                pIGlobalInterfaceTable->Release();
            }
            if (pv != NULL)
                pv->Release();
        }
        CoUninitialize();
        fprintf(stdout, "Thread going away\n");
    }
    return 0;
}

int main(int argc, char* argv[]) {
    HRESULT hr;
    if (FAILED(hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) {
        fprintf(stderr, "Error CoInitializeEx: 0x%08x\n", hr);
    }
    else {
        struct register_interface_thread state;
        state.dwCookie = 0;
        state.hInterfaceRegistered = CreateEventEx(NULL, TEXT("hInterfaceRegistered"), CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
        state.hShouldClose = CreateEventEx(NULL, TEXT("hShouldClose"), CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);

        HANDLE hThread = CreateThread(NULL, 0, RegisterInterfaceThread, &state, 0, NULL);
        if (hThread == NULL) {
            DWORD err = GetLastError();
            fprintf(stderr, "Error CreateThread: 0x%08x\n", err);
            hr = err;
        }
        else {
            DWORD waitResult;
            if (WAIT_OBJECT_0 != (waitResult = WaitForSingleObject(state.hInterfaceRegistered, INFINITE))) {
                DWORD err = GetLastError();
                fprintf(stderr, "Error WaitForSingleObject: returned 0x%x; error=0x%08x\n", waitResult, err);
                hr = err;
            }
            else {
                fprintf(stdout, "Successfully waited for hInterfaceRegistered; dwCookie=0x%x\n", state.dwCookie);
                IGlobalInterfaceTable *pIGlobalInterfaceTable;
                if (FAILED(hr = CoCreateInstance
                    (
                    CLSID_StdGlobalInterfaceTable,
                    NULL,
                    CLSCTX_INPROC_SERVER,
                    IID_IGlobalInterfaceTable,
                    (void **)&pIGlobalInterfaceTable
                    ))) {
                    fprintf(stderr, "CoCreateInstance(StdGlobalInterfaceTable) failed with hresult 0x%x\n", hr);
                }
                else {
                    IUnknown *pv = NULL;
                    DWORD start_time = GetTickCount();
                    DWORD i;
                    for (i = 0; i != 10000; i++) {
                        if (FAILED(hr = pIGlobalInterfaceTable->GetInterfaceFromGlobal(state.dwCookie, IID_IRemoteProxyFactory, (LPVOID*)&pv))) {
                            fprintf(stderr, "GetInterfaceFromGlobal failed with hresult 0x%x\n", hr);
                            break;
                        }
                        else {
                            pv->Release();
                        }
                    }
                    DWORD end_time = GetTickCount();
                    DWORD difference = end_time - start_time;
                    fprintf(stdout, "%u iterations completed in %ums\n", i, difference);
                    pIGlobalInterfaceTable->Release();
                }
                if (!SetEvent(state.hShouldClose)) {
                    DWORD err = GetLastError();
                    fprintf(stderr, "SetEvent(hShouldClose) failed; err=0x%x\n", err);
                    hr = err;
                }
                else {
                    if (WAIT_OBJECT_0 != (waitResult = WaitForSingleObject(hThread, INFINITE))) {
                        DWORD err = GetLastError();
                        fprintf(stderr, "Error WaitForSingleObject(hThread): returned 0x%x; error=0x%08x\n", waitResult, err);
                        hr = err;
                    }
                    else {
                        printf("successfully joined thread.\n");
                    }
                }
            }
        }
    }
    return hr;
}

これを windbg で実行すると、タイプ ライブラリが 10000 回再読み込みされることが確認されます。

bp KERNELBASE!CreateFileW "r $t0 = @$t0 + 1; g"
bp OLEAUT32!LoadTypeLibEx "r $t1 = @$t1 + 1; g"
g
r $t0, $t1
$t0=000000000000c35c $t1=0000000000002712
于 2015-04-08T09:20:14.123 に答える