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

Delphi Discussion :

Delphi 5 et threads en nombre


Sujet :

Delphi

  1. #1
    Membre du Club
    Inscrit en
    Avril 2007
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 9
    Par défaut Delphi 5 et threads en nombre
    Bonjour,

    Me voici confronté a un problème de thread...
    J'ai fait un petit serveur a partir des composants TServerClientWinsocket.
    Ce serveur de fonctionnais plutot pas mal jusqu'au jour ou je me suis retrouvé avec plus de 2000 connectés.

    On dirais qu'il n'est pas possible de creer plus de 2000 threads

    En effet je créé un thread pour chacun des connectés.
    J'ai pas forcément choisi la bonne solution a ce moment la mais je n'imaginais pas dépasser les 500 connectés simultanément.

    Voici donc mes questions :
    Comment depasser cette limite de 2000 threads ? (je ne sais pas par quoi ni comment elle est fixée)

    D'autre par j'utilise les directives suivantes :
    {$A+,B-,C+,D+,E-,F-,G+,H+,I+,J+,K-,L+,M-,N+,O-,P+,Q+,R+,S-,T-,U-,V+,W+,X+,Y+,Z1}
    {$MINSTACKSIZE $00004000}
    {$MAXSTACKSIZE $00100000}
    {$IMAGEBASE $00400000}
    {$APPTYPE GUI}

    Il semblerais que quand je joues avec ces valeurs le nombre de threads maximum pouvant etre créé change (le hic c'est que je depasse jamais 2000)

    Dans l'idéal je souhaiterais repousser la limite des threads a l'espace mémoire de ma machine. Au pire j'aimerais bien repousser cette limite au moins a 5000 voir 10 000.

    Merci de votre aide qui me sortira d'un mauvais pas ^^

    PS : Je vous fait grace du contexte qui est un peu plus compliqué que ca...
    Pool de threads et tout un tas de choses ignobles pour faire quelques calculs prédictifs...

  2. #2
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 041
    Par défaut
    Cela doit être un joli Serveur, mais avec le MemoryManager de D5, dépassé les 16 Thread ça doit commencé à réduire les performances, cherche FastMM pour D5 il remplace, le MemoryManager qui va maintenir les perfs élevés malgré bcp de Thread, ...

    Maintenant 2000 Threads, j'ai un doute sur la capacité à dépasser ce nombre, car souvent le programme se plombe de trop en perf ...

    Maintenant, que fait ton programme ?
    Tu pourrais partager les Thread pour plusieurs clients ? genre 256 clients par Threads selon le type de traitement (si c'est du chat, pas de soucis, si c'est de la DB, disons que 16 seraient plus raisonnables ?)

    Ensuite, as-tu essayé le multi-instance avec une DB pour gérer les données partagés ? DB, synchronisation par Message, ...

    Ensuite, tu pourrais jouer avec un serveur global ou s'effectue la 1ère connexion, mais il te redirige sur un serveur de charge différent (tu envoie au client la nouvelle IP/Port pour se connecter à un autre serveur ...)
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Membre du Club
    Inscrit en
    Avril 2007
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 9
    Par défaut Que fait ce petit serveur ^^
    Voila grosso modo ce que ce serveur fait :

    Y a en frontal un Thread pool servant a gerer les connections socket.
    Ce thread pool augmente son nombre de threads de traitements selon l'activitée du processeur et du nombre de connections.

    Ces threads sont spécialisés dans le traitement des données entrantes.

    D'autre part il y a un autre thread pool qui lui se charge d'ecrire les données résultantes vers les différents clients. (ce pool est géré de la meme manière que le frontal)

    Jusque la rien de bien méchant. A ceci pret que mon nombre de client a augmenté (ce de manière exponentielle)

    Ce qui fait que grosso modo je me retrouve avec pas moins de 10 000 socket...

    D'autre part apres avoir recu des données d'un client je les passe a une 3 eme série de threads qui eux vont s'occuper de vérifier la cohérence des calculs fait par le client par rapport a ceux du serveur pour résoudre les soucis.

    Les calculs faits par le serveur sont eux gérés par un 4eme pool de threads...

    Voila a peu pres comment le code veut fonctionner ^^

    Maintenant je me retrouve a devoir augmenter le nombre de threads du pool frontal ainsi que du pool sortant pour conserver de la réactivité.

    Ce qui fait que j'ai fini par atteindre cette fameuse limite de 2000 dont j'aimerais bien me passer ^^.
    Je dois avouer que réarchitecturer ce code reviendrais a me jetter par la fenetre...
    Le pire dans tout ca c'est que pour optimiser un peu le tout j'avais choisis une machine avec plusieurs processeurs physiques histoire que la gestion des threads ne bouffe pas trop de temps par rapport a l'execution du thread lui meme...

  4. #4
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 041
    Par défaut
    Effectivement, vu le nombre de Thread que tu arrives déjà à lancer, j'avais deviné que c'était une machine plutot assez solide ...

    Alors, avec les composants de ScktComp (TServerSocket\TClientSocket) de D5, je les ai surtout utilisé en mode non blocking, l'as tu essayé ? Mais le mode non blocking ne doit être qu'un thread caché dans l'implémentation ...

    J'ignore totalement ce que ça donne avec autant de connection, j'ai utilisé en thread les TTcpClient/Serveur de D7, mais j'en suis pas fan, et j'ai essayé pour voir le thread avec ceux de ScktComp, mais jamais j'ai fait de tel charge.

    Maintenant quelle est la durée de vie d'une connexion ?
    Car j'ai cru comprendre qu'un groupe de thread s'occupait déjà de la lecture dans les sockets, avec je suppose un timeOut assez court pour lire séquentiellement un ensemble de client, et ne pas trop les bloquer ...

    les clients doivent avoir un réponse instantanée (genre quelques secondes maximum) ? Je ne peux pas t'aider énormément, mais je vais essayé de te poser les questions que tu ne te poses plus, mais il est clair qu'il faut réduire le nombre de thread, car je crois que si je me souvient des test que j'avais fait mon maximum fut aussi dans les 2000, juste en les créants, avec un execute qui n'était qu'un sleep(1000) répété jusqu'à demande de fermeture

    il est a savoir que la framework .net, même si je suis pas fan, a bcp de fonctionnalité pour les TheadPool ...

    Je t'avoue que je n'ai jamais fait de programme avec autant de thread sauf pour des tests à la con, j'ai fait des serveurs de tri (logistique genre entrepot vetement ou tri postal), qui n'ont que quelques connections mais surtout bcp de requête par seconde ...

    il faut que tu fouilles dans ce genre de sujet http://support.microsoft.com/kb/280087/fr

    Ton programme ça me fait penser au SETI pour les calculs des étoiles ...

    Maintenant, j'ai vu des serveurs HTTP (ISAPI Delphi) gérant plus de 800 connexions sans broncher pour un produit auquel j'ai brièvement participé, et il y a avait 800 thread un pour chaque client, mais il me semble que les connexions à la DB et autres étaient canalisé dans un seul (en fait il y a avait des Serveur COM+ pour répartir les charges) ... c'était un vrai archi multi-tiers
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Membre du Club
    Inscrit en
    Avril 2007
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 9
    Par défaut
    Avec des socket blocantes mon nombre de threads actifs serais beaucoup plus elevé :p

    Le pool de threads frontal agit comme suit :
    Ma liste de sockets et decoupé en blocs de X connections.
    Mon pool frontal s'occupe lui de parcourir chacun des blocs.
    Par exemple pour 1000 connections j'ai 20 threads qui regardent dans leur bloc de 50 connections non blocantes.

    En gros ca donne ca :
    |------|------|------| ... |------| // Connections
    |---+--|--+---|--+--| ... |---+--| // La ou le thread est
    |---T1-|--T2--|--T3-| ... |---TX-| // numéro de thread

    Les infos récupérées par la gestion des connections sont poussées au pool de thead de gestion (verif des données cohérence ect)

    Pour l'ecriture on a le meme genre de truc.

    Mes clients ne peuvent pas souffir d'attendre trop ;-p
    Le temps de réponse doit etre inférieur a la 1/2 seconde.
    Si ce temps de réponse est plus grand sur quelques clients ca va mais si il est alongé pour tous les clients je me retrouve a devoir resoudre plus d'informations calculées chez le client qui a attendu.
    Du coup je tombe dans la deche parce que l'effet de bord peut tout faire ecrouler.

    D'autre part j'ai essayé moi aussi de depasser les 2000 threads en parralèlle apres etre tombé sur cet os et en effet une fois arrivé a 2000 ca casse...

    Le pire c'est que mes clients peuvent etre connectés de 15 secondes a plus de 24h....

    Je crois qu'au final je vais finir par laisser tomber ce projet qui a ocupé une bonne partie de ma vie depuis ces 3 dernières années. J'aurais essayé de le sauver ^^

  6. #6
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 041
    Par défaut
    J'ignore si ce projet est libre ou pas, si tu as du budget pour t'en occuper, car dans le métier on peut pas tout faire comme on le voudrait sans tunes ... si tu as besoin de main d'oeuvre, je pourrais toujours essayés de te prêter main forte soit en freelance, soit en pro via mon employeur.

    Je n'arrive pas à comprendre un truc, ... les sockets non bloquantes vont déclencher l'évènement OnRead pour te signaler qu'il faut lire non ? alors qu'une socket bloquante tu vas tenter de lire à un instant T, si tu n'as rien après un TimeOut (10 ms ? 0,5s / 50), tu passe à la suivante ...

    tu sais que chaque socket NON bloquante lance aussi un Thread ... c'est peut-être cela qu'il faut revoir ... sinon comme je te le disais fait un répartiteur, vu déjà ton application, je pense que c'est une modification qui ne te fera pas peur ...

    Situation Actuelle
    - Une Machine (Une IP)
    - Un Programme
    - Une IP
    - Un Port xxxx

    Tout le monde se connecte sur ce contexte, donc tu peux le revoir de cette manière, en faisant un routeur :

    - Une Machine Routeur
    - Un Programme Routeur
    - Un Port Routeur xxxx (celui utilisé actuellement par les clients)
    - Un Ensemble de Machine (Plusieurs IP y compris celle du routeur)
    - Un Ensemble de Programme (IP égale ou différente, Port Différent pour éviter les mélanges de port client et port serveur sur la même machine)
    - Un Ensemble de Port ...

    Un Exemple

    Client A se connecte sur Routeur
    Routeur consulte une table qui lui indique la liste des ses Répartiteurs de Charge (rc) (c'est un programme lancé en multi-instance, la table de routage contient l'IP et le Port à utiliser cela peut être la même machine comme cela peut-être une autre machine)

    le Routeur dispose de rc1 (localhost: xxxx+1) , rc2 (localhost: xxxx+2), rc3 (distant: xxxx+3) ...
    rc1 a 500 clients (plusieurs se sont déconnectés depuis, biensur chaque répartiteurs communique sur le port xxxx-1, la confirmation de connexion, la déconnexion volontaire ou forcée, les demandes et résultats de calcul, ...)
    rc2 à 700 clients (pas chance plein de clients de longue durée)
    rc3 à 600 clients (...)

    donc le Routeur choisit rc1
    il envoit une trame au client A, lui indiquant l'IP et le Port, et un ID unique de connexion sur l'ensemble de réseau de charge où il doit établir sa connexion, ton client a été routé sur un Répartiteurs de Charge ... il est connecté sur rc1 et non sur Routeur.
    Le Routeur lui stocke dans une table (mémoire, fichier comme tu veux), l'ID du Client A et sur quelques Répartiteurs, il tourne ...
    Le Client A reçoit donc l'IP: Port, il confirme qu'il a compris au Routeur, le Routeur tue la connexion, pendant ce temps, Client A se connecte sur le Répartiteurs ...

    Ensuite, pour chaque client dans les Répartiteurs de Charge, tu as un Thread avec socket Bloquant qui lui est totalement dédié, ton routeur fait en sorte de ne pas dépasser 1024 sur chaque, et si cela se produit il va envoyer sur le port xxxx-2 une commande (un service qui est Gardien de Répartition tourne sur chaque machine pouvant être Répartiteurs de Charge, bien sur le Routeur à la liste dans IP disponible) à un PC pour lui demander de lancer un nouveau répartiteur, ainsi il peut ouvrir rc4 avec 0 clients, qui prendra tous les nouveaux clients jusqu'à ce qu'un autre rc soit moins occupés ou jusqu'à ce que le routeur créé rc5...

    A un moment Client A va faire une demande de calcul, il envoi sa trame sur rc1, rc1 lui transmet à Routeur la demande en spécifiant l'ID unique de A, et comme tu n'as que 3 répartiteurs sur 2 machines différentes sur le Routeur, tu as 1 socket avec son thread par connexion, donc 3 sur le port xxxx-1 qui est le port pour l'ensemble de Répartiteurs, et 2 sur le xxxx-2 pour le Gardien ... tu as tout loisir de lancer autant de thread que de calcul car tu n'auras pas 2000 calculs simulanés, mais tu peux le prévoir car ton routeur pourrait aussi avec des Répartiteurs de Calculs (après tout ... autant continuer le routage pour l'ensemble)

    Donc Routeur fait son calcul, il l'envoi à rc1 qui se charge via un ID unique de savoir a qui il doit envoyer ce calcul ...

    Voilà, c'est une architecture totalement réparti ...
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  7. #7
    Membre du Club
    Inscrit en
    Avril 2007
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 9
    Par défaut
    Je dois t'avouer que ce n'est qu'un petit projet personnel.
    Faire comme les grands c'est pas donné a tout le monde
    Je vais essayer de coder correctement un répartiteur de charge en suivant tes propositions d'architechture.
    Espérant que j'y arrive

Discussions similaires

  1. Threads et nombre aléatoire
    Par dwarfman78 dans le forum C++
    Réponses: 61
    Dernier message: 28/06/2007, 14h35
  2. Nombre de Threads d'un programme
    Par c-ve dans le forum Delphi
    Réponses: 2
    Dernier message: 18/05/2006, 14h59
  3. Contrôler le nombre de thread simultané
    Par player734 dans le forum POSIX
    Réponses: 3
    Dernier message: 30/10/2005, 22h56
  4. Les nombres complexe et delphi
    Par wikers dans le forum Langage
    Réponses: 3
    Dernier message: 04/08/2005, 11h47
  5. [net][Sockets] Quel est le nombre maximal de threads?
    Par itsmii dans le forum Entrée/Sortie
    Réponses: 3
    Dernier message: 06/05/2004, 10h48

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