我被告知的一切都说WCF应该至少和远程处理一样快。我有一个特定的场景,然而,它甚至没有接近,我想知道是否有人可以发现一些明显的我做错了。我正在研究用wcf替换远程处理以进行进程内appdomain通信繁重的可能性。这是代码:
[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
更新:事实证明,这只是初始设置对于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
答案 0 :(得分:19)
在大多数情况下,花费时间来设置和拆除WCF频道。其他狮子分享的时间似乎是通过在调试器中运行来消耗的。请记住,这是非正式的类型测试.. :)
我能够重现你的数字,所以我从那里开始。这表明WCF数字<远>大于远程数字的3倍。
通过缓存频道工厂(以及相应的远程处理对象),数字会下降,以便WCF 仅比远程数字大2倍。
在尝试了十几个其他不同的调整后,唯一一个似乎削减数字的任何实际可测量时间的是清除所有调试服务行为(默认添加) - 这导致大约100ms。还不足以让人感到兴奋。
然后,在一时兴起,我在发布配置中运行调试器外部的代码。数字下降到大致相当于远程数字,如果不是更好。额头砸了桌子并称它完成了。
简而言之,您应该看到大致相同,使用WCF可以获得更好的性能并获得更好的编程模型来启动。
remoting 1 test run in 347ms
wcf 1 test run in 1544ms
remoting 2 test run in 493ms
wcf 2 test run in 324ms
remoting 3 test run in 497ms
wcf 3 test run in 336ms
remoting 4 test run in 449ms
wcf 4 test run in 289ms
remoting 5 test run in 448ms
wcf 5 test run in 284ms
remoting 6 test run in 447ms
wcf 6 test run in 282ms
remoting 7 test run in 439ms
wcf 7 test run in 281ms
remoting 8 test run in 441ms
wcf 8 test run in 278ms
remoting 9 test run in 441ms
wcf 9 test run in 278ms
remoting 10 test run in 438ms
wcf 10 test run in 286ms
注意 - 此代码已被完全混淆。我道歉。 :)
using System;
using System.ServiceModel;
using System.Runtime.Serialization;
[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 AppDomain dom = AppDomain.CreateDomain("wcf domain", null);
static WorkerObject dcnt = dom.CreateInstanceFromAndUnwrap(System.Reflection.Assembly.GetExecutingAssembly().Location, typeof(WorkerObject).FullName) as WorkerObject;
static ChannelFactory<IWorkerObject> fact = new ChannelFactory<IWorkerObject>(new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), "net.pipe://localhost/the_channel");
static IWorkerObject chan = fact.CreateChannel();
static AppDomain remdom = AppDomain.CreateDomain("remoting domain", null);
static IWorkerObject remoteObject;
static void Main(string[] args)
{
remoteObject = remdom.CreateInstanceFromAndUnwrap(System.Reflection.Assembly.GetExecutingAssembly().Location, typeof(WorkerObject).FullName) as IWorkerObject;
dcnt.OpenChannel();
int numberOfIterations = 10;
for (int i = 1; i <= numberOfIterations; i++)
{
run_rem_test(i);
run_wcf_test(i);
}
fact.Close();
dcnt.CloseChannel();
AppDomain.Unload(dom);
AppDomain.Unload(remdom);
}
static void run_rem_test(int iteration)
{
RunTest("remoting " + iteration, remoteObject);
}
static void run_wcf_test(int iteration)
{
RunTest("wcf " + iteration, chan);
}
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(typeof(WorkerObject));
m_host.AddServiceEndpoint(typeof(IWorkerObject), new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), "net.pipe://localhost/the_channel");
// cache our ServiceBehaviorAttribute, clear all other behaviors (mainly debug)
// and add our ServiceBehavior back
//
var b = m_host.Description.Behaviors[0] as ServiceBehaviorAttribute;
m_host.Description.Behaviors.Clear();
m_host.Description.Behaviors.Add(b);
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",
};
}
}
答案 1 :(得分:1)
我发现在调试模式下使用visual studio时,使用netnamedpipes的wcf比远程调用慢。如果将其更改为发布模式,无论是否附加调试器,wcf都与远程处理一样快。