IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Système de cache hiérarchique (besoins de conseils)


Sujet :

C++

  1. #1
    Membre très actif Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Par défaut Système de cache hiérarchique (besoins de conseils)
    Bonjour,

    Pour un projet perso, je me retrouve à avoir besoins d'un système de cache de données en mémoire. Un système typique clé/valeur. Mais pas seulement.

    Le truc c'est qu'au lieu d'un simple système associatif, je veux un système hiérarchique, un tree en fait. La raison c'est que certaines opérations d'invalidation du cache doivent également automatiquement invalider les éléments "enfants". Quand je parle d'invalider le cache, c'est détruire les données pour une certaines clé et donc aussi les clés enfants.

    L'autre contrainte, c'est que l'accès en lecture doit être rapide, si possible O(1) en moyenne.

    Comment implémenter ce genre de solution ?

    Voilà ce que j'ai fait:
    Déjà pour commencer, j'ai trouvé cette class:
    tree.hh: an STL-like C++ tree class
    http://www.aei.mpg.de/~peekas/tree/

    J'ai donc pensé à créer un nouveau container qui réunit à la fois ce genre de tree pour le storage et aussi un boost::unordered_map pour un accès rapide à partir d'une clé.

    Le tree contient des shared_ptr sur ce genre de type:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct data {
      std::string key;
      std::string value;
      // destucteur...
    };
    En parallèle j'ai un unordered_map<string key, weak_ptr<data> >

    Quand j'ajoute une nouvelle entrée dans le tree, un std::pair<string, weak_ptr<data> > est également ajouté dans le map.

    Le destructeur de la struct data se charge de détruire son entrée associée dans le unordered_map.
    Le truc c'est que les 2 containers (tree et map) soient synchronisés, d'où l'usage de shared_ptr et weak_ptr pour que le ref counting ne soit pas corrompu.

    Voilà ce que j'ai. Ca semble fonctionner pas mal mais je n'ai pas trop regardé pour ce qui est de l'exception safety..
    (j'utilise gcc 4.5 donc les types utilisés sont dans std:: )

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    #include <memory>
    #include <algorithm>
    #include <unordered_map>
    #include <string>
    #include <boost/noncopyable.hpp>
    #include "tree.hh"
     
    template<typename Key = std::string, typename Value = std::string>
    struct cache : boost::noncopyable
    {
    	struct cache_node;
     
    	typedef Key key_type;
    	typedef Value value_type;
     
    	typedef std::shared_ptr<cache_node> shared_node;
    	typedef std::weak_ptr<cache_node> weak_node;
     
    	typedef tree<shared_node> tree_type;
    	typedef std::unordered_map<key_type, weak_node> table_type;
     
    	typedef typename tree_type::iterator iterator;
     
    	struct cache_node : boost::noncopyable
    	{
    		cache_node(const key_type& key, const value_type& value, table_type& lookup)
    			: key(key), value(value), lookup(lookup)
    		{ }
     
    		~cache_node() { 
    			typename table_type::iterator it = lookup.find(key);
    			if (it != lookup.end()) {
    				lookup.erase(it);
    			}
    		}
     
    		key_type key;
    		value_type value;
    		table_type& lookup;
    	};
     
     
    	void add(const key_type& key, const value_type& value)
    	{
    		typename table_type::const_iterator it = table.find(key);
    		if (it != table.end()) {
    			quick_del(it);
    		}
    		typename tree_type::iterator top = nodes.begin();
    		shared_node p(new cache_node(key, value, table));
    		nodes.insert(top, p);
    		table[key] = weak_node(p);
    	}	
     
    	void add(iterator& parent, const key_type& key, const value_type& value)
    	{
    		typename table_type::const_iterator it = table.find(key);
    		if (it != table.end()) {
    			quick_del(it);
    		}
    		shared_node p(new cache_node(key, value, table));
    		nodes.append_child(parent, p);
    		table[key] = weak_node(p);
    	}	
     
    	void add(const key_type& parent, const key_type& key, const value_type& value)
    	{
    		iterator itp = location(parent);
    		if (valid(itp)) {
    			add(itp, key, value);
    		}
    	}
     
    	iterator location(const key_type& key) const
    	{
    		iterator itr = nodes.end();
    		typename table_type::const_iterator it = table.find(key);
    		if (it != table.end()) {
    			shared_node s = it->second.lock();
    			itr = find(nodes.begin(), nodes.end(), s);
    		}
    		return itr;
    	}
     
    	bool valid(const iterator& it) const
    	{
    		return it != nodes.end();
    	}
     
     
    	void del(const key_type& key)
    	{
    		typename table_type::const_iterator it = table.find(key);
    		if (it != table.end()) {
    			quick_del(it);
    		}
    	}	
     
    	value_type get(const key_type& key) const
    	{
    		typename table_type::const_iterator it = table.find(key);
    		if (it != table.end()) {
    			shared_node s = it->second.lock();
    			return s->value;
    		}
    		return value_type();
    	}
     
    	bool has(const key_type& key) const
    	{
    		return table.find(key) != table.end();
    	}		
     
    	void clear()
    	{
    		nodes.clear();
    	}
     
    private:
    	void quick_del(const typename table_type::const_iterator& it)
    	{
    		typename tree_type::iterator itr;
    		{
    			shared_node s = it->second.lock();
    			itr = find(nodes.begin(), nodes.end(), s);
    		}
    		if (itr != nodes.end()) {
    			nodes.erase(itr);
    		}
    	}	
     
    private:	
    	table_type table;
    	tree_type nodes;
     
    };
    Coté userland:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    cache<std::string, std::string> c;
     
    c.add("key1", "value_1");
    c.get("key1"); // "value_1"
     
    c.add("key1", "key2", "value_2"); // key1 as parent
    c.has("key2"); // true
     
    c.del("key1"); // key1 et key2 sont détruits

  2. #2
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Par défaut
    Faudrait voir aussi ce que tu cherches à mettre en cache exactement : emplacement des données d'origine, type et taille des données, emplacement du cache lui-même, fréquence d'accès, durée de validité prévue des données, etc. Parce que l'on n'utilise pas tout à fait les mêmes méthodes pour mettre en cache une ressource Internet (ultra-lente), LAN (lente), disque ("normale") ou mémoire (rapide)...

    Une autre notion importante est : ton cache doit-il être transparent, ou pas ? Dit autrement : quand tu as un miss, est-ce que le cache va chercher la donnée pour honorer la demande quoi qu'il arrive, ou va-t'il renvoyer une erreur et obliger le système appelant à aller chercher la donnée et la remettre en cache ?
    La première méthode est bien plus efficace et rapide, mais est aussi nettement moins "généraliste". La seconde est générale, mais moins performante. Question de choix, donc.

    Plus ta gestion de cache est complexe, plus elle est inadaptée à un cache rapide... De plus, il faut aussi faire attention à ne pas trop entrer en "conflit" avec le système d'exploitation et/ou le CPU lui-même qui ont également un cache !!
    En effet, si tu implémentes un cache sur un cache déjà existant, tu as plus de chances de perdre des performances que de les améliorer.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  3. #3
    Membre très actif Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Par défaut
    Merci bien pour cette réponse Mac LAK.

    Oui, c'est vrai que j'ai oublié de préciser le domaine d'utilité de mon truc: cache de données d'un site web.
    Je fais des tests avec un cache<std::string, std::string>. Les valeurs sont des fragments de page (voir des pages complètes).
    La taille des données est donc de quelques 10aine de kilo au plus, mais il se pourrait qu'il y ait des centaines de données stockées.

    Et donc pour l'instant j'utilise la 2ième méthode: lors d'un cache miss, c'est un système autre que le moteur de cache qui va construire et storer la nouvelle valeur qui sera ensuite placée dans le cache.

    Bon, j'ai fait quelques essais. Avec ce système de cache, quand je bypass complètement le sgdb (mysql en socket unix sur le même server), je peux délivrer les pages 10 fois plus vite (dans un cas avec 100% de cache hits).

    Plus ta gestion de cache est complexe, plus elle est inadaptée à un cache rapide... De plus, il faut aussi faire attention à ne pas trop entrer en "conflit" avec le système d'exploitation et/ou le CPU lui-même qui ont également un cache !!
    En effet, si tu implémentes un cache sur un cache déjà existant, tu as plus de chances de perdre des performances que de les améliorer.
    Je n'ai absolument pas considéré ça. En fait j'y connais rien
    va falloir que je regarde ces histoires de cache CPU. Toujours est-il que mon architecture est très naïve je pense. Mon type cache est un membre d'une class qui est chargée de traiter les actions selon les urls demandées. Ca persiste entre les différentes requêtes (c'est du fastcgi).

  4. #4
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    Typiquement un cache a une taille fixe, donc on fait une file dans un tableau.
    Apparemment, tu as besoin d'avoir la capacité d'enlever un élément où qu'il soit dans le cache, donc il ne faut pas utiliser une file, mais une liste doublement chaînée ; les éléments du tableau seront donc des noeuds.
    Tu veux un index, rajoute le dans un tableau séparé.
    Tu veux une hiérarchisation, rajoute des maillons dans tes noeuds.

    Ce genre de chose n'est clairement pas facile à faire de manière optimale en terme de placement mémoire en utilisant la STL.
    Je te conseille de regarder du côté de Boost.Intrusive peut-être.

  5. #5
    Membre très actif Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Par défaut
    Merci loufoque pour cet éclairage.

    J'avais effectivement regardé Boost.Intrusive (et même Boost.Graph), mais ça m'a paru un brin complexe. Entre temps je suis tombé sur le tree.hh mentionné plus haut, donc bon, j'ai continué avec ça.. pour l'instant du moins.

    Tu veux une hiérarchisation, rajoute des maillons dans tes noeuds.
    Je n'ai pas tout à fait compris ce que tu entends par maillons dans les noeuds.
    En tout cas, la seul chose que j'arrive à concevoir pour arriver à retirer des noeuds n'importe où et possiblement tous les noeuds "enfant"... est une structure en arbre.

    Ce genre de chose n'est clairement pas facile à faire de manière optimale en terme de placement mémoire en utilisant la STL.
    Ouais et ça j'avoue, j'y connais pas grand chose pour les histoires de placement mémoire. Je fais confiance à la STL et à tree.hh qui à l'air bien foutu quand même. Bon, je n'ai pas besoins non plus d'un truc hyper optimisé. Là la soluce que j'ai actuellement me conviendrait tout à fait, sauf que je n'ai pas encore testé avec beaucoup d'éléments dans le cache.

  6. #6
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Par défaut
    Citation Envoyé par metagoto Voir le message
    Oui, c'est vrai que j'ai oublié de préciser le domaine d'utilité de mon truc: cache de données d'un site web.
    Bon, donc, tu peux (si besoin) utiliser des trucs "complexes", ça sera toujours infiniment plus rapide qu'un transfert HTTP.
    De plus, dans ce cas précis, tu n'as que de très très faibles chances d'entrer en conflit avec un cache existant, car il n'y a normalement pas de cache au niveau des sockets : le cache des navigateurs, justement, est propre aux navigateurs eux-mêmes et n'influence pas le système et/ou les autres programmes utilisant Internet.

    Citation Envoyé par metagoto Voir le message
    La taille des données est donc de quelques 10aine de kilo au plus, mais il se pourrait qu'il y ait des centaines de données stockées.
    Sauf si tu as un besoin impératif d'utiliser la mémoire, moi, à ta place, j'utiliserais plutôt le disque dur pour ça... Au moins, sauf rares exceptions, tu ne seras pas limité par la taille des données et/ou leur nombre.
    De plus, tu peux différer les invalidations en flinguant immédiatement la table d'index du cache, puis lançant un thread basse priorité qui effacera le fichier sur le disque sur le temps libre de la machine. Les lectures sont également simplifiées, car les fonctions "read" (Linux) ou "ReadFile" (Windows) prennent indifféremment une socket ou un fichier comme source !!

    Tu pourras même utiliser les fonctions sendfile (Linux) ou TransmitFile (Windows) qui te permettront de vider directement un fichier dans une socket sans le "lire" manuellement...

    En cas de besoin de performances, tu peux toujours accélérer ton cache en le mettant dans un RAMDisk.

    Citation Envoyé par metagoto Voir le message
    Et donc pour l'instant j'utilise la 2ième méthode: lors d'un cache miss, c'est un système autre que le moteur de cache qui va construire et storer la nouvelle valeur qui sera ensuite placée dans le cache.
    Ce qui n'est pas spécialement gênant en soi, mais ce n'est pas l'idéal non plus... Sauf à "câbler" des fonctions de lecture / mise en cache à ton moteur "général" de cache, via l'utilisation de templates et/ou de pointeurs de fonction et/ou d'héritage.
    Pour ma part, je préfèrerais l'approche par héritage, en laissant les fonctions de lecture/mise en cache virtuelles pures, et en les implémentant dans une classe dérivée spécialisée pour ton besoin.

    Citation Envoyé par metagoto Voir le message
    Toujours est-il que mon architecture est très naïve je pense. Mon type cache est un membre d'une class qui est chargée de traiter les actions selon les urls demandées. Ca persiste entre les différentes requêtes (c'est du fastcgi).
    Disons qu'il faut faire attention avec la RAM sur un serveur, en plus : tu n'es pas tout seul...
    Si tes pages sont "calculées", les sauver sur le disque reste plus rapide que de les recalculer, et en plus le cache disque de l'OS va t'aider.
    Si tu tiens absolument à les charger en RAM à 100%, je te conseille l'approche via un RAMDisk et un cache par fichiers malgré tout.

    Mais bon : que les données soient sur le disque dur ou en RAM, ça ne change par l'organisation de ton "index" de cache, qui doit exister en RAM quoi qu'il arrive.
    Comme l'a précisé Loufoque, normalement, un cache est de taille fixe, et organisé en "lignes" (c'est à dire des portions pouvant être invalidées individuellement).
    Mais dans ton cas, l'organisation en "lignes" n'est pas totalement adéquate, car une "page" peut très bien n'avoir aucune page "enfant", comme elle peut en avoir des tonnes...

    Pour ma part, j'aurais tendance à regarder du côté d'une structure B-Tree dont le parcours se ferait via les divers paramètres donnés à ton CGI. La structure même du B-Tree permet un parcours le plus réduit possible (l'arbre est équilibré), et une invalidation avec tous les descendants comme tu le souhaites. Chaque noeud devra contenir bien sûr les données adéquates :
    • Un nom de fichier OU le contenu,
    • La taille des données mise en cache,
    • L'âge des données (un timestamp, en l'occurrence), qui sert aussi de flag d'invalidation.
    • La date du dernier accès.

    En parcourant l'arbre, quand tu vois des données invalides, tu peux directement retirer le nœud. Si jamais ton cache est "plein", là aussi un simple parcours avec suppression du plus ancien te permettra de récupérer de l'espace.

    Tu peux optimiser un peu en mettant dans un vecteur les données d'âge (tu fais le lien avec un indice de tableau dans l'arbre, et le pointeur sur le nœud dans le vecteur). La taille du vecteur te donne alors directement la taille du cache, et tu peux par exemple faire très rapidement les opérations suivantes :
    • Calcul de la taille occupée par le cache.
    • Suppression des données les plus anciennes par parcours séquentiel.
    Bien sûr, il faut utiliser au maximum les constructeurs/destructeurs des nœuds / cellules du vecteur afin de correctement lier les deux structures : la suppression d'une cellule détruit le nœud correspondant, qui détruit ses fils, chaque fils invalidant sa propre entrée dans le vecteur => la boucle est bouclée.

    Pour le calcul d'âge, tu as un truc très simple et redoutablement efficace : les deadlines (ou dates-limite). Le principe est le suivant :
    • Une deadline est la réunion de deux entiers (32 ou 64 bits) :
      • Un compteur ordinal système : sous Windows, on utilise par exemple GetTickCount ou QueryPerformanceCounter. Sous Linux, il faudra convertir gettimeofday en un entier 64 bits.
      • Une durée de validité, convertie dans l'unité du compteur système. Sous Linux, par exemple, ce seront des microsecondes, et sous Windows des millisecondes (GetTickCount) ou une valeur sans unité fixe (QueryPerformanceCounter).
    • A l'initialisation, on arme la deadline en stockant dans son compteur le compteur système courant, augmenté de la durée de validité.
    • Lors de l'accès à la deadline, on "réarme" cette dernière en ajoutant de nouveau sa durée de validité au compteur système courant.
    • On peut déterminer si une deadline est expirée par simple comparaison entre son compteur et le compteur système courant : si le premier est inférieur au second, alors la deadline a dépassé sa durée de validité, et on la détruit. Sinon, elle est valide, et on peut (au choix) la réarmer automatiquement ou pas.



    Est-ce à peu près clair pour toi ?
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  7. #7
    Membre très actif Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Par défaut
    Ok, y a du boulot
    Merci

    Pour commencer, il est vrai que j'avais pensé à utiliser de simples fichiers text. En fait, avoir plusieurs types de backends différents selon les besoins. Une interface commune puis le reste est délégué au backend choisi. Niveau implémentation, une simple host class template avec des policies adaptées devrait faire l'affaire.

    A voir pour la suite, mais j'ai l'impression que pour l'instant je n'ai pas besoins d'un système qui permette des invalidations basées sur des timestamps ou des deadlines. La structure en tree qui me convient (du moins, je pense) permet de fractionner les infos et de n'invalider que les éléments impactés par certains évènements qui se produisent durant la vie de l'application web. Par exemple, truc con, un mec ajoute un commentaire sur la page d'un article. Le système va invalider le cache des commentaires de l'article. RAS. Si un admin efface l'article, le système va virer le cache de l'article et ses caches enfants dans lesquels il y aura les commentaires.

    Pour le problème de la taille du cache, c'est clair qu'il faut que je regarde ça de plus près. Mon index actuel est une hash table qui me permet de choper un pointer sur la donnée. Il n'y a donc pas d'ordre. Je pourrais voir pour rajouter un deuxième index ordonné par les fréquences d'accès aux élements et donc pouvoir effacer les moins utilisés si besoins.
    Quelque part, je n'ai pas véritablement besoins d'avoir un tree super optimisé pour les parcours. Le parcours se fait lors d'une invalidation pour effacer un subtree. De part et d'autre de cette opération, il faudra fetcher les données de la base et recalculer la page, bref, c'est déjà coûteux en temps. En rajouter par dessus ne changera pas grand chose. Cependant, je vais quand même regarder de plus près Boost.Intrusive car plusieurs types de trees sont implémentés dont les b-trees.

    Aussi, je ne suis pas du tout expert là dedans, mais y a peut être moyen de préallouer un segment en mémoire puis de jouer avec des placements new ? A voir..

    En tout cas, merci bien pour tes conseils

  8. #8
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Par défaut
    Citation Envoyé par metagoto Voir le message
    Ok, y a du boulot
    Ah ça, le cache, c'est pas forcément le truc le plus immédiat qui existe...

    Citation Envoyé par metagoto Voir le message
    Aussi, je ne suis pas du tout expert là dedans, mais y a peut être moyen de préallouer un segment en mémoire puis de jouer avec des placements new ? A voir..
    C'est à dire ? Peux-tu expliciter un peu plus ?
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  9. #9
    Membre très actif Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Par défaut
    [11.10] What is "placement new" and why would I use it?
    http://www.parashift.com/c++-faq-lit...html#faq-11.10

    Alors c'est vrai qu'il y a du boulot, mais je tiens quand même à rappeler que ma solution initiale fonctionne bien... du moins, en l'état actuel du projet

  10. #10
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Par défaut
    Citation Envoyé par metagoto Voir le message
    [11.10] What is "placement new" and why would I use it?
    http://www.parashift.com/c++-faq-lit...html#faq-11.10
    Bof, je ne vois pas trop l'intérêt pour ton application en tout cas... Tu n'as pas de tailles fixes pour tes données, et si tu utilises un container "tout prêt", il gère déjà sa propre mémoire donc autant lui foutre la paix.

    Citation Envoyé par metagoto Voir le message
    Alors c'est vrai qu'il y a du boulot, mais je tiens quand même à rappeler que ma solution initiale fonctionne bien... du moins, en l'état actuel du projet
    Ah, t'as demandé des conseils, hein, donc te plains pas d'avoir eu la réponse...

    Plus sérieusement, ça te donne une idée de ce qui peut être fait pour arriver à un système plus performant, tout en étant (en plus !) d'une meilleure généricité.

    Retiens aussi le "truc" des transferts directs (TransmitFile / sendfile) si tu utilises des fichiers pour stocker tes données en cache, ainsi que la possibilité d'utiliser un RAMDisk.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  11. #11
    Membre Expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Par défaut
    Ca a sûrement était envisagé lors de l'étude de l'existant, mais est-ce qu'un cache comme Squid ne ferait pas l'affaire : http://www.squid-cache.org/ ?

  12. #12
    Membre très actif Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Par défaut
    Citation Envoyé par Mac LAK Voir le message
    Retiens aussi le "truc" des transferts directs (TransmitFile / sendfile) si tu utilises des fichiers pour stocker tes données en cache, ainsi que la possibilité d'utiliser un RAMDisk.
    Oui, je saurai faire bon usage de ces conseils le moment venu

    Citation Envoyé par seriousme Voir le message
    Ca a sûrement était envisagé lors de l'étude de l'existant, mais est-ce qu'un cache comme Squid ne ferait pas l'affaire : http://www.squid-cache.org/ ?
    Pas vraiment d'après ce que j'ai vu. Squid est une application en tant que tel et trop spécifique au http. En revanche il y a de bonnes infos sur leur site donc ça peut toujours aider d'un point de vue théorique. Merci

Discussions similaires

  1. Réponses: 4
    Dernier message: 20/05/2005, 13h30
  2. .htaccess - url rewriting, besoin de conseils
    Par giminik dans le forum Apache
    Réponses: 2
    Dernier message: 25/04/2005, 20h18
  3. [C#] [ADO.NET] Besoin de conseil
    Par djsbens dans le forum Accès aux données
    Réponses: 8
    Dernier message: 01/04/2005, 15h04
  4. Réponses: 3
    Dernier message: 24/12/2004, 12h21
  5. Réponses: 1
    Dernier message: 06/01/2003, 07h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo