第一次调用时WCF序列化很慢

时间:2011-12-26 09:02:04

标签: wcf performance serialization

我正在使用.Net 3.5 SP1,使用默认的WCF序列化程序 - DataContractSerializer。 我有这个简单的界面:

[ServiceContract]
public interface IService
{
    [OperationContract]
    void RecieveInteger(int value);

    [OperationContract]
    void RecieveBigDataType(BigDataType value);
}

我的客户执行以下操作:

  1. 调用'RecieveInteger'来预热服务。
  2. 调用'RecieveBigDataType'10次并测量性能。
  3. 测量10次调用'RecieveBigDataType',我发现第一次调用比其他调用慢得多。看起来WCF第一次需要序列化“BigDataType”类型的速度非常慢。 有什么想法让第一次通话更快?

2 个答案:

答案 0 :(得分:1)

根据MSDN,对于XmlSerializer,

通过在启动时调用FromTypes来初始化XmlSerializer

第一次XmlSerializer遇到一个类型时,它会生成执行序列化的代码,然后它会缓存该代码供以后使用。但是,如果在XmlSerializer上调用FromTypes静态方法,则会强制XmlSerializer立即生成并缓存计划序列化类型所需的代码。这减少了第一次序列化特定类型所花费的时间。以下示例显示了此方法。

static void OnApplicationStart()
{
  Type[] myTypes = new Type[] { Type.GetType("customer"), Type.GetType("order") };
  XmlSerializer.FromTypes( myTypes );
}

我知道你使用的是使用DataContractSerializer的WCF,但也许有一些方法可以做同样的事情。

从这里开始:http://msdn.microsoft.com/en-us/library/ff650685.aspx

答案 1 :(得分:0)

我在使用 DataContractJsonSerializer 时遇到了几乎相同的问题。在我的情况下,DataContractJsonSerializer.WriteObject(..) 的第一次调用比对同一对象的其他调用多花 1.3 秒。
老实说,序列化对象有一些接口,因此必须定义 KnownTypes

我发现的唯一解决方法是在应用程序启动时运行 Task 并序列化已知类型的虚拟对象。
有趣的是,虚拟对象的线程池序列化时间比 GUI 少 0.5 秒。

Task.Run(() =>
{
    var knownTypes = new[] { typeof(ServiceImpl_1), typeof(ServiceImpl_2), typeof(ServiceImpl_3)};
    var ser = new System.Runtime.Serialization.Json.DataContractJsonSerializer
                (
                    typeof(IService),
                    new DataContractJsonSerializerSettings { KnownTypes = knownTypes }
                );

    using(var ms = new MemoryStream())
    {
        foreach(var tp in knownTypes)
        {
            object inst = null;
            try
            {
                foreach(var ctorInf in tp.GetConstructors())
                {
                    try
                    {
                        var prInfos = ctorInf.GetParameters();
                        if(prInfos.Length == 0)
                        {
                            inst = Activator.CreateInstance(tp);
                        }
                        else
                        {
                            var parList = new object[prInfos.Length];
                            for(int i = 0; i < prInfos.Length; i++)
                            {
                                parList[i] = prInfos[i].ParameterType.IsValueType ? Activator.CreateInstance(prInfos[i].ParameterType) : null;
                            }
                            inst = Activator.CreateInstance(tp, parList);
                        }
                    }
                    catch(Exception)
                    {
                        continue;
                    }
                    ser.WriteObject(ms, inst);
                }
            }
            catch(Exception exc) {}
        }
    }
}