Все, что мне сказано, говорит о том, что WCF должен быть не менее быстрым, чем удаленный. У меня есть конкретный сценарий здесь, однако, где он даже не близок, и мне интересно, может ли кто-нибудь обнаружить что-то очевидное, что я делаю неправильно. Я изучаю возможность замены удаленного с помощью wcf для интенсивного подъема внутрипроцессорной связи внутри процесса. Здесь код:
[ServiceContract]
interface IWorkerObject
{
[OperationContract] Outcome DoWork(Input t);
}
[DataContract]
[Serializable]
class Input
{
[DataMember] public int TaskId { get; set; }
[DataMember] public int ParentTaskId { get; set; }
[DataMember] public DateTime DateCreated { get; set; }
[DataMember] public string TextData { get; set; }
[DataMember] public byte[] BinaryData { get; set; }
}
[DataContract]
[Serializable]
class Outcome
{
[DataMember] public string Result { get; set; }
[DataMember] public string TextData { get; set; }
[DataMember] public byte[] BinaryData { get; set; }
}
class Program
{
static void Main(string[] args)
{
run_rem_test();
run_wcf_test();
run_rem_test();
run_wcf_test();
}
static void run_rem_test()
{
var dom = AppDomain.CreateDomain("remoting domain", null);
var obj = dom.CreateInstanceFromAndUnwrap(System.Reflection.Assembly.GetExecutingAssembly().Location, typeof(WorkerObject).FullName) as IWorkerObject;
RunTest("remoting", obj);
AppDomain.Unload(dom);
}
static void run_wcf_test()
{
var dom = AppDomain.CreateDomain("wcf domain", null);
var dcnt = dom.CreateInstanceFromAndUnwrap(System.Reflection.Assembly.GetExecutingAssembly().Location, typeof(WorkerObject).FullName) as WorkerObject;
var fact = new ChannelFactory<IWorkerObject>(new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), "net.pipe://localhost/the_channel");
var chan = fact.CreateChannel();
dcnt.OpenChannel();
RunTest("wcf", chan);
fact.Close();
dcnt.CloseChannel();
AppDomain.Unload(dom);
}
static void RunTest(string test, IWorkerObject dom)
{
var t = new Input()
{
TextData = new string('a', 8192),
BinaryData = null,
DateCreated = DateTime.Now,
TaskId = 12345,
ParentTaskId = 12344,
};
var sw = System.Diagnostics.Stopwatch.StartNew();
for( var i = 0; i < 1000; i++ )
dom.DoWork(t);
sw.Stop();
Console.WriteLine("{1} test run in {0}ms", sw.ElapsedMilliseconds, test);
}
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
class WorkerObject : MarshalByRefObject, IWorkerObject
{
ServiceHost m_host;
public void OpenChannel()
{
m_host = new ServiceHost(this);
m_host.AddServiceEndpoint(typeof(IWorkerObject), new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), "net.pipe://localhost/the_channel");
m_host.Open();
}
public void CloseChannel()
{
m_host.Close();
}
public Outcome DoWork(Input t)
{
return new Outcome()
{
TextData = new string('b', 8192),
BinaryData = new byte[1024],
Result = "the result",
};
}
}
Когда я запускаю этот код, я получаю числа, которые выглядят так:
remoting test run in 386ms wcf test run in 3467ms remoting test run in 499ms wcf test run in 1840ms
UPDATE: Оказывается, это просто первоначальная настройка, которая так дорого стоит для WCF (спасибо, Zach!). Поскольку я воссоздавал AppDomains в каждом тесте, я платил эту цену снова и снова. Здесь обновленный код:
[ServiceContract]
interface IWorkerObject
{
[OperationContract] Outcome DoWork(Input t);
}
[DataContract]
[Serializable]
class Input
{
[DataMember] public int TaskId { get; set; }
[DataMember] public int ParentTaskId { get; set; }
[DataMember] public DateTime DateCreated { get; set; }
[DataMember] public string TextData { get; set; }
[DataMember] public byte[] BinaryData { get; set; }
}
[DataContract]
[Serializable]
class Outcome
{
[DataMember] public string Result { get; set; }
[DataMember] public string TextData { get; set; }
[DataMember] public byte[] BinaryData { get; set; }
}
class Program
{
static void Main(string[] args)
{
var rem_dom = AppDomain.CreateDomain("remoting domain", null);
var rem_obj = rem_dom.CreateInstanceFromAndUnwrap(System.Reflection.Assembly.GetExecutingAssembly().Location, typeof(WorkerObject).FullName) as IWorkerObject;
var wcf_dom = AppDomain.CreateDomain("wcf domain", null);
var mgr_obj = wcf_dom.CreateInstanceFromAndUnwrap(System.Reflection.Assembly.GetExecutingAssembly().Location, typeof(WorkerObject).FullName) as WorkerObject;
var fact = new ChannelFactory<IWorkerObject>(new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), "net.pipe://localhost/the_channel");
var wcf_obj = fact.CreateChannel();
var rem_tot = 0L;
var wcf_tot = 0L;
mgr_obj.OpenChannel();
for( var i = 0; i < 10; i++ )
{
rem_tot += RunTest("remoting", i, rem_obj);
wcf_tot += RunTest("wcf", i, wcf_obj);
}
fact.Close();
mgr_obj.CloseChannel();
AppDomain.Unload(rem_dom);
AppDomain.Unload(wcf_dom);
Console.WriteLine();
Console.WriteLine("remoting total: {0}", rem_tot);
Console.WriteLine("wcf total: {0}", wcf_tot);
}
static long RunTest(string test, int iter, IWorkerObject dom)
{
var t = new Input()
{
TextData = new string('a', 8192),
BinaryData = null,
DateCreated = DateTime.Now,
TaskId = 12345,
ParentTaskId = 12344,
};
var sw = System.Diagnostics.Stopwatch.StartNew();
for( var i = 0; i < 1000; i++ )
dom.DoWork(t);
sw.Stop();
Console.WriteLine("{1,-8} {2,2} test run in {0}ms", sw.ElapsedMilliseconds, test, iter);
return sw.ElapsedMilliseconds;
}
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
class WorkerObject : MarshalByRefObject, IWorkerObject
{
ServiceHost m_host;
public void OpenChannel()
{
m_host = new ServiceHost(typeof(WorkerObject));
m_host.AddServiceEndpoint(typeof(IWorkerObject), new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), "net.pipe://localhost/the_channel");
m_host.Open();
}
public void CloseChannel()
{
m_host.Close();
}
public Outcome DoWork(Input t)
{
return new Outcome()
{
TextData = new string('b', 8192),
BinaryData = new byte[1024],
Result = "the result",
};
}
}
Этот код дает такие номера:
remoting 0 test run in 377ms wcf 0 test run in 2255ms remoting 1 test run in 488ms wcf 1 test run in 353ms remoting 2 test run in 507ms wcf 2 test run in 355ms remoting 3 test run in 495ms wcf 3 test run in 351ms remoting 4 test run in 484ms wcf 4 test run in 344ms remoting 5 test run in 484ms wcf 5 test run in 354ms remoting 6 test run in 483ms wcf 6 test run in 346ms remoting 7 test run in 491ms wcf 7 test run in 347ms remoting 8 test run in 485ms wcf 8 test run in 358ms remoting 9 test run in 494ms wcf 9 test run in 338ms remoting total: 4788 wcf total: 5401