Включенный модульный тест C # и файл кода C пытаются передать управляемый обратный вызов неуправляемому коду. Код фактически выполняется, но переменная count никогда не увеличивается. Таким образом, тест не пройден.
Тот факт, что он выполняется вообще, означает, что он загружает dll, находит ссылку для метода DoCallBack () и, кажется, вызывает метод. Но ничего не происходит. Так что что-то не так.
Вы, вероятно, хотите знать, зачем пытаться это сделать? И вам интересно, есть ли лучший подход? Итак, конечная цель - создать «хак», чтобы потоки по доменам приложений работали практически с той же производительностью, что и в одном домене.
По следующей ссылке вы найдете более быструю, на сегодняшний день, технику по кросс-производительности AppDomain. Команда MS .Net AddIn предлагает «FastPath», который значительно улучшает производительность удаленного взаимодействия. Мы запустили их пример на .Net 3.5, и он работает очень быстро после помещения их контрактов AddIn в GAC.
http://blogs.msdn.com/b/clraddins/archive/2008/02/22/add-in-performance-what-can-you-expect-as-you-cross-an-isolation-boundary-and-how-to-make-it-better-jesse-kaplan.aspx
Теперь давайте обсудим некоторые сопутствующие расчеты времени, чтобы понять, почему это все еще недостаточно быстро для наших нужд. Обычное междоменное удаленное взаимодействие предлагает примерно 10000 вызовов в секунду для метода с нулевыми аргументами. С опцией FastPath, которая увеличивается до 200 000 вызовов в секунду. Но, сравнивая это с C # вызова метода интерфейса с нулевыми аргументами (в том же домене), он выполняет более 160 000 000 операций в секунду на той же машине, что и другие тесты.
Таким образом, даже техника FastPath все еще в 1000 раз медленнее, чем простой вызов метода интерфейса. Но почему нам нужна лучшая производительность?
Или требования к производительности заключаются в том, чтобы устранить все узкие места программного обеспечения из приложения, связанного с ЦП, которое обрабатывает миллиарды кортежей информации в считанные минуты с помощью многоядерной и распределенной технологии.
Но новым требованием к функции будет возможность предлагать архитектуру AddIn или Plugin, чтобы компоненты могли загружаться или выгружаться без остановки остальной системы. Единственный способ сделать это эффективно в .Net - использовать отдельные домены приложений.
Обратите внимание, что мы не хотим передавать данные через домены приложений, все они работают независимо друг от друга параллельно.
Но что касается потоков, очень неэффективно иметь отдельный поток, работающий в каждом из сотен доменов приложений. В этом случае они конкурируют за процессор и вызывают огромную потерю производительности при переключении контекста.
Итак, план здесь заключается в том, чтобы иметь основной или основной домен, который имеет пул потоков и по очереди вызывает каждый домен AppDomain, который нужно сделать, и позволяет ему работать некоторое время. Так что это означает совместную многопоточность (чтобы избежать переключения контекста). Поэтому домены приложений вернутся, чтобы основной домен приложений перешел к другим.
К сожалению, каждый AppDomain не может работать очень долго независимо до того, как закончится работа, и ему нужно вернуться в основной домен, чтобы позволить другому AppDomain работать ... так что время производительности 200 000 в секунду из-за техники FastPath приведет к значительное снижение общей производительности из-за кросс-доменных вызовов.
В отличие от PInvoke, приведенного ниже, мы измерили время с помощью StopWatch, чтобы производить более 90 000 000 - это 90 миллионов - вызовов в секунду на той же машине, что и другие тесты. Поэтому есть надежда, что к тому времени обратный вызов P / Invoking в другом домене приложений будет по-прежнему позволять выполнять миллионы операций в секунду.
90 миллионов в секунду намного ближе к нашей потребности в переключении потоков между доменами приложений.
Хорошо. Теперь вернемся к этому тесту. Цель этого простого модульного теста состоит в том, чтобы сначала получить простые обратные вызовы из неуправляемого в управляемый код, работающий .... после этого следующим шагом будет создание отдельного домена AppDomain, обратный вызов делегата к нему и передача в неуправляемый код проверить производительность междоменного обратного вызова.
Мы знаем, что все это возможно, мы видим обсуждение и примеры в Интернете ... но хотя приведенный ниже код кажется простым ... он просто не работает, как ожидалось.
Вот неуправляемый код, созданный как DLL без параметра командной строки / CLR:
#include <windows.h>
typedef void (CALLBACK *PFN_MYCALLBACK)();
int count = 0;
extern "C" {
__declspec(dllexport) void __stdcall DoSomeStuff() {
++count;
}
}
extern "C" {
__declspec(dllexport) void __stdcall DoCallBack(PFN_MYCALLBACK callback) {
PFN_MYCALLBACK();
}
}
Вот код модульного теста C #.
using System.Runtime.InteropServices;
using System.Security;
using NUnit.Framework;
namespace TickZoom.Callback
{
[SuppressUnmanagedCodeSecurity]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void MyCallback();
[TestFixture]
class CrossAppDomainTesting
{
public int count;
[Test]
public void TestCallback()
{
NativeMethods.DoCallBack(
delegate()
{
++count;
});
Assert.AreEqual(1, count);
}
[Test]
public void TestDate()
{
NativeMethods.DoSomeStuff();
}
}
public static class NativeMethods
{
[SuppressUnmanagedCodeSecurity]
[DllImport("CrossAppDomain.dll")]
public static extern void DoSomeStuff();
[SuppressUnmanagedCodeSecurity]
[DllImport("CrossAppDomain.dll")]
public static extern void DoCallBack(MyCallback callback);
}
}