En fait, j'ai eu un problème semblable, mais quelque peu différente problème de paramètres.
Ma requête porte avec 2 types de chaînes - relativement court de mesure de 60 à 100 chars et de plus avec de 100 à 1000 octets (en moyenne autour de 300).
Mon cas d'utilisation doit également prendre en charge unicode texte, mais un pourcentage relativement faible des chaînes en fait non-anglais caractères.
Dans mon cas d'utilisation, j'ai été d'exposer chaque Chaîne de propriété en tant que natif de la Chaîne, mais la structure de données sous-jacente a été un byte[] holding unicode octets.
Mon cas d'utilisation exige également la recherche et le tri par le biais de ces chaînes, l'obtention de sous-chaînes et d'autres communes de la chaîne des opérations. Mon dataset mesures dans les millions.
La mise en œuvre de base ressemble à quelque chose comme ceci:
byte[] _myProperty;
public String MyProperty
{
get
{
if (_myProperty== null)
return null;
return Encoding.UTF8.GetString(value);
}
set
{
_myProperty = Encoding.UTF8.GetBytes(value);
}
}
Les performances de ces conversions, même lorsque vous effectuez une recherche et de tri a été relativement faible (était d'environ 10 à 15%).
C'était bien un temps, mais je voulais réduire les frais généraux supplémentaires.
La prochaine étape a été de créer un tableau fusionné pour toutes les chaînes de caractères dans un objet (un objet titulaire, soit: 1 court et 1 long chaîne de caractères, ou de 4 et 1 longue chaîne).
donc, il y aurait un byte[] pour chaque objet, et ne nécessitent 1 octet pour chacune des chaînes (enregistrer leurs longueurs qui sont toujours < 256). même si vos chaînes peuvent être plus longs à 256, et l'int est encore moins cher que le de 12 à 16 octets de surcharge pour le byte[].
Cela réduit de beaucoup le byte[] les frais généraux, et ajouté un peu de complexité, mais aucun impact sur les autres à la performance (le codage de passe est relativement cher par rapport à la matrice de copie de jeu).
cette application ressemble à quelque chose comme ceci:
byte _property1;
byte _property2;
byte _proeprty3;
private byte[] _data;
byte[] data;
//i actually used an Enum to indicate which property, but i am sure you get the idea
private int GetStartIndex(int propertyIndex)
{
int result = 0;
switch(propertyIndex)
{
//the fallthrough is on purpose
case 2:
result+=property2;
case 1:
result+=property1;
}
return result;
}
private int GetLength(int propertyIndex)
{
switch (propertyIndex)
{
case 0:
return _property1;
case 1:
return _property2;
case 2:
return _property3;
}
return -1;
}
private String GetString(int propertyIndex)
{
int startIndex = GetStartIndex(propertyIndex);
int length = GetLength(propertyIndex);
byte[] result = new byte[length];
Array.Copy(data,startIndex,result,0,length);
return Encoding.UTF8.GetString(result);
}
si la lecture ressemble à ceci:
public String Property1
{
get{ return GetString(0);}
}
Le setter est dans le même état d'esprit, de copier les données d'origine dans deux tableaux (entre 0 commencer à startIndex, et entre startIndex+longueur de longueur) , et de créer un nouveau tableau avec les 3 tableaux (dataAtStart+NewData+EndData) et réglez la longueur de la matrice appropriée à la variable locale.
J'étais toujours pas satisfait de la mémoire enregistré, et le très difficile le travail de la mise en œuvre manuelle pour chaque propriété, alors j'ai construit une mémoire compresser système de pagination qui utilise incroyablement rapides QuickLZ pour compresser une pleine page.
Cela m'a donné beaucoup de contrôle sur le temps-mémoire compromis (qui est essentiellement la taille de la page).
Le taux de compression pour mon cas d'utilisation (par rapport à la plus efficace byte[] magasin) approche les 50% (!). J'ai utilisé une taille de page de env 10 chaînes par page et groupées des propriétés similaires ensemble (qui ont tendance à avoir des données similaires).
Cela a ajouté une surcharge supplémentaire de 10 à 20% (sur le haut de l'encodage/décodage de passage, qui n'est toujours nécessaire). Le mécanisme de pagination caches récemment accédé à des pages jusqu'à une taille configurable.
Même sans la compression de cette mise en œuvre permet de définir un facteur fixe sur le rétroprojecteur pour chaque page.
L'inconvénient majeur de mon actuel de la mise en œuvre de la cache de la page, c'est que la compression n'est pas thread-safe (sans elle, il n'y a pas ce problème).
Si vous êtes intéressé dans le comprimé mécanisme de pagination laissez-moi savoir (j'ai été à la recherche d'une excuse pour ouvrir la source).