我使用委托从非托管代码调用托管代码。当我在默认的AppDomain中调用托管代码时,我每次调用的平均值为5.4ns。当我拨打第二个AppDomain时,我每次呼叫的测量值为194ns。 (默认VS2017 x86发布配置,未在调试器下运行)。
为什么在调用不是默认值的AppDomain时性能会低得多?由于我来自非托管端,不了解AppDomains,我希望直接进入目标域。但是,性能打击意味着委托调用默认域然后编组到真实目标。单步执行反汇编时,我确实看到了UM2MDoADCallBack
。它显示在UMThunkStub.asm
WrongAppDomain:
下
如何防止这种不必要的封送并直接调用特定的AppDomain?
我用来测试的代码如下。
#pragma unmanaged
#include <wtypes.h>
#include <cstdint>
#include <cwchar>
typedef void (__stdcall *ManagedUpdatePtr)();
struct ProfileSample
{
static uint64_t frequency;
uint64_t startTick;
wchar_t* name;
int count;
ProfileSample(wchar_t* name_, int count_)
{
name = name_;
count = count_;
LARGE_INTEGER win32_startTick;
QueryPerformanceCounter(&win32_startTick);
startTick = win32_startTick.QuadPart;
}
~ProfileSample()
{
LARGE_INTEGER win32_endTick;
QueryPerformanceCounter(&win32_endTick);
uint64_t endTick = win32_endTick.QuadPart;
uint64_t deltaTicks = endTick - startTick;
double nanoseconds = (double) deltaTicks / (double) frequency * 1000000000.0 / count;
wchar_t buffer[128];
swprintf(buffer, _countof(buffer), L"%s - %.4f ns\n", name, nanoseconds);
OutputDebugStringW(buffer);
if (!IsDebuggerPresent())
MessageBoxW(nullptr, buffer, nullptr, 0);
}
};
uint64_t ProfileSample::frequency = 0;
int CALLBACK
WinMain(HINSTANCE, HINSTANCE, PSTR, INT)
{
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
ProfileSample::frequency = frequency.QuadPart;
ManagedUpdatePtr GetManagedUpdatePtr();
auto managedUpdate = GetManagedUpdatePtr();
//Warm stuff up
for ( size_t i = 0; i < 100; i++ )
managedUpdate();
const int num = 10000000;
{
ProfileSample p(L"ManagedUpdate", num);
for ( size_t i = 0; i < num; i++ )
managedUpdate();
}
return 0;
}
#pragma managed
using namespace System;
using namespace System::Diagnostics;
using namespace System::Runtime::InteropServices;
ref struct ManagedObject : MarshalByRefObject
{
ManagedUpdatePtr
GetManagedUpdatePtr()
{
auto delegate = gcnew Action(this, &ManagedObject::ManagedUpdate);
IntPtr fPtr = Marshal::GetFunctionPointerForDelegate(delegate);
return (ManagedUpdatePtr) fPtr.ToPointer();
}
void ManagedUpdate()
{
//Debug::WriteLine("\n\nManagedUpdate ({0})", (Object^) AppDomain::CurrentDomain->FriendlyName);
}
};
ManagedUpdatePtr
GetManagedUpdatePtr()
{
auto pluginDomain = AppDomain::CreateDomain("Plugin Domain");
auto managedObject = (ManagedObject^) pluginDomain->CreateInstanceAndUnwrap("ManagedHelper", "ManagedObject");
return managedObject->GetManagedUpdatePtr();
}