2016-04-07 9 views
0

Je travaille actuellement sur un projet qui génère du code basé sur d'autres codes. Essentiellement en utilisant le langage de programmation lui-même comme un DSL.C# améliorer la sérialisation binaire

L'un des objectifs de générateur est un binary DataContract serializer et les ToBytes générés pour la classe suivante

[DataContract] 
public partial class Root 
{ 
    [DataMember] 
    public int Number { get; set; } 

    [DataMember] 
    public Partial[] Partials { get; set; } 

    [DataMember] 
    public IList<ulong> Numbers { get; set; } 
} 

DEVIENT ceci:

public int Size 
{ 
    get 
    { 
     var size = 8; 
     // Add size for collections and strings 
     size += Partials.Sum(entry => entry.Size); 
     size += Numbers.Count * 8; 

     return size;    
    } 
} 
public byte[] ToBytes() 
{ 
    var index = 0; 
    var bytes = new byte[Size]; 

    return ToBytes(bytes, ref index); 
} 
public byte[] ToBytes(byte[] bytes, ref int index) 
{ 
    // Convert Number 
    Buffer.BlockCopy(BitConverter.GetBytes(Number), 0, bytes, index, 4);; 
    index += 4; 
    // Convert Partials 
    // Two bytes length information for each dimension 
    Buffer.BlockCopy(BitConverter.GetBytes((ushort)(Partials == null ? 0 : Partials.Length)), 0, bytes, index, 2); 
    index += 2; 
    foreach(var value in Partials ?? Enumerable.Empty<Partial>()) 
    { 
     value.ToBytes(bytes, ref index); 
    } 
    // Convert Numbers 
    // Two bytes length information for each dimension 
    Buffer.BlockCopy(BitConverter.GetBytes((ushort)(Numbers == null ? 0 : Numbers.Count)), 0, bytes, index, 2); 
    index += 2; 
    foreach(var value in Numbers ?? Enumerable.Empty<ulong>()) 
    { 
     Buffer.BlockCopy(BitConverter.GetBytes(value), 0, bytes, index, 8);; 
     index += 8; 
    } 
    return bytes; 
} 

Maintenant, même difficile ce qui est vraiment rapide, je suis à la recherche d'un moyen pour accélérer toutes les utilisations de Buffer.BlockCopy(BitConverter.GetBytes. Il semble toujours être un gaspillage de ressources pour créer un nouveau petit byte[] pour chaque conversion, puis copier que lorsque j'ai déjà le byte[] et la position.

Des idées pour améliorer le code?

Mise à jour: Basé sur le commentaire @adrianm Je remplacerai foreach par des boucles for-array pour les tableaux et le type nullable wrap dans les instructions if. L'utilisation de structures comme dans another thread n'est pas souhaitée. Je préfère utiliser les classes et les attributs [DataContract]. Aussi pour la conformité Linux, je ne peux pas utiliser WinApi.

Update2: Ajout du reste du code généré. Merci à un commentaire version future comprendra

if (index + Size > bytes.Length) 
    // Some error handling 
+1

Les allocations et la copie d'octets sont vraiment rapides. Ma conjecture est que vous pourriez augmenter la vitesse plus si vous vous concentrez sur d'autres parties dans le code comme l'utilisation de 'for loops' au lieu de' foreach' et 'if' au lieu de' ?? Enumerable.Empty' – adrianm

+0

Typiquement c'est 'struct' et [' Marshal.StructureToPtr'] (http://stackoverflow.com/a/3278956/1997232), si vous avez besoin de * fast *, alors les méthodes winapi sont [le chemin] (http://stackoverflow.com/a/24027952/1997232) pour aller. – Sinatr

+0

@adrianm bon point. J'ai utilisé 'foreach' car il est compatible avec toutes les collections mais en regardant [ArrayEnumerator] (https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/Array.cs#L2546) aurait pu être le choix d'essor. Merci pour les commentaires. – Toxantron

Répondre

0

Je a vu la mise en œuvre de BitConverter et leur utilisation de pointeurs dangereux et pour créer le byte[]. Je voudrais l'utiliser à l'intérieur du code généré comme:

*byte pointer = bytes; 
*((int*)pointer + pos) = Number; 
pos += 4; 

Mais dans ce cas, cela devrait être une méthode dangereuse et je ne suis pas sûr de ce que cela va faire au code plus réussi là-dedans.

+1

L'utilisation de méthodes 'unsafe' ne fait rien pour le reste du code managé. 'Unsafe'! =' non managé' – Jcl