We have developed some system which works with DB queues and which components reside in a separate Windows Services. We have an idea to execute all the components within a single executable but in separated AppDomains. The main purpose is to prevent the whole system crashing when a single components crash.
After performing few tests we have faced the problem of Cross-AppDomain calls being too slow. I tried to sign the assemblies with the strong name and put them to GAC and also applied LoaderOptimization.MultiDomain(Host), but the performance is still not acceptable: 14 000 000 calls/sec with simple single AppDomain calls and 90 000 calls/sec in Cross-Domain calls mode. In the application two calls are performed: first one from Default AppDomain to the Non-Default AppDomain, the second one - in the opposite direction. 90 000 calls/sec is very good result, but considering the simplicity of the test application and after projecting the complexity of our system to the multiple AppDomain approach we figured out that it is way too slow.
The main question is: Is there a way to significantly speed up the cross-domain calls? Maybe some sort of checks can be eliminated?
The code:
class Program
{
public class TestMessage : MarshalByRefObject { }
public class TestClass : MarshalByRefObject
{
private TestClass() { }
public void TestMethod(TestMessage message) { }
public static TestClass Create(bool defaultDomain)
{
if (defaultDomain)
{
return TestClass.createDefaultDomain();
}
return TestClass.createInNewDomain();
}
private static TestClass createDefaultDomain()
{
return new TestClass();
}
private static TestClass createInNewDomain()
{
AppDomain appDomain = AppDomain.CreateDomain("NewDomain");
return appDomain.CreateInstance(
typeof(TestClass).Assembly.FullName,
typeof(TestClass).FullName,
true, BindingFlags.NonPublic | BindingFlags.Instance,
null, null, null, null)
.Unwrap() as TestClass;
}
}
[STAThread]
[LoaderOptimization(LoaderOptimization.MultiDomain)]
static void Main(string[] args)
{
TestClass testClass = TestClass.Create(true);
TestMessage message = new TestMessage();
int calls = 0;
Stopwatch sw = Stopwatch.StartNew();
while (sw.ElapsedMilliseconds < 10000)
{
testClass.TestMethod(message);
calls++;
}
sw.Start();
Console.WriteLine("{0:N3}", calls / sw.Elapsed.TotalSeconds);
}
}