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 :

[Algorithme] Copie liste de fichiers avec 10 threads


Sujet :

Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Avatar de Sub0
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2002
    Messages
    3 573
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 573
    Par défaut [Algorithme] Copie liste de fichiers avec 10 threads
    Salut!

    Je développe actuellement un programme de copie. J'utilise 10 threads de copie. (un peu comme LeetchFtp). Je voudrais que l'utilisateur puisse sélectionner autant de fichiers qu'il le veut et que le programme détecte lorsqu'un thread se libère pour poursuivre la copie de cette liste. Mon problème, est que je ne sais pas quelle est la meilleure solution à utiliser dans ce genre de cas. Je pensais créer une classe 'TFichier' pour enregistrer les informations des fichiers sources (nom, taille, attributs, position de la copie, temps restant pour a copie, etc) et un tableau dynamique : ListFichier: Array Of TFichier;

    Qu'en pensez-vous ?
    Auriez-vous des idées d'algorithme plus performant ?
    TCollection est une piste intérressante ?

    Merci d'avance.

  2. #2
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 089
    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 089
    Par défaut
    L'utilisation d'un Array ou d'une Collection n'a que peu d'importance, dans ton cas, je ne crois pas qu'une ThreadList soit non plus utile mais je la recommande tout de même

    Regarde simplement autour de Section Critique, tu pourras éviter les conflits de lecture Ecriture ...

    Tes 10 Threads sont lancés en permanence ? dommage d'utiliser de la ressource à ne rien faire ...

    Tu as une demande de télécharger 27 fichiers, tu lances tes threads, et tu comptes le nombre de Thread Actif (un entier encapsulé dans un objet singleton avec une section critique sur l'accesseur, ce compteur est augmenté dans le constructeur d'un Thread, et diminue à la fin du Execute ou dans le Destroy si tu mets FreeOnTerminate à True), tu as donc 10 fichiers en Cours, et 17 en attente, pour ce qui est des progessions, ça tu vois avec les objets FTP, je l'ai fait avec un TNMFTP créé dans le Thread avec un AS400 derrière, comme tu as des fichiers en attente, tu lance un Timer ou un Thread de Queue

    Ensuite, tu as un Timer, qui scrute la liste (le Thread de Queue en faite), si il y a des fichiers à télécharger, tu regarde le compteur, si il est à 10, tu ne fais rien, si il y en a moins, tu lance autant que possible pour le nombre de fichiers restant ...

    Donc, en gros F1 sur TThreadList, TCriticalSection, les Pointeurs, ...
    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 Expert
    Avatar de Sub0
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2002
    Messages
    3 573
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 573
    Par défaut
    Réponse très intérressante. Merci ShaiLeTroll.

    Cela dit, j'ai déjà développé ma classe de thread. Cette classe regroupe les propriétés et méthodes nécessaires au transfert de données. Voici sa déclaration (simplifiée) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Const MaxThreads = 10;
     
    Type
      THttpThread = Class(TThread)
      ...
      End;
     
    Var HttpThreads: Array [0..MaxThreads - 1] Of THttpThread;
    Tout ceci fonctionne parfaitement bien, je n'ai pas envie de tout recoder... C'est juste la partie "gestion de la liste des fichiers et distribution des threads que je dois réaliser.

    Ce que je comptais faire était une déclaration similaire : Une classe d'objet "TFichier" avec son tableau dynamique typé, et un timer qui se chargerait de parcourir cette liste à la recherche des fichiers à transmettre et de rechercher les threads libres pour les allouer à ces fichiers.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Type
      TFichier = Class
        ThreadIndex: Integer;
        ...
      End;
     
    Var ListFichier: Array Of TFichier;
    L'objet TFichier sera libéré dès que son transfert sera terminé et le tableau dynamique possèdera alors un "élément" libre. Si l'utilisateur ajoute de nouveaux fichiers à copier (pendant la copie), il faudra que je parcours le tableau dynamique à la recherche d'un index libre pour stocker le fichier... ou bien si il n'ya plus de place libre, augmenter la taille du tableau avec SetLength... c'est lourd, non ?

  4. #4
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 931
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 931
    Billets dans le blog
    6
    Par défaut
    pour ma part, je vois bien un TQueue que tu charges avec des Push(fichier) et que chaque thread se terminant va inspecter d'un Pop pour se relancer...
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  5. #5
    Membre Expert
    Avatar de Sub0
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2002
    Messages
    3 573
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 573
    Par défaut
    Citation Envoyé par tourlourou
    pour ma part, je vois bien un TQueue que tu charges avec des Push(fichier) et que chaque thread se terminant va inspecter d'un Pop pour se relancer...
    Voilà! C'est ça qu'il me faut.

  6. #6
    Membre éprouvé

    Homme Profil pro
    Inscrit en
    Octobre 2003
    Messages
    908
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 908
    Par défaut
    Pourquoi ne pas utiliser un sémaphore pour la gestion du nombre de thread ?

    Chaque fois qu'un thread termine sa copie il libère une place du sémaphore et un autre thread peut commencer.

  7. #7
    Membre éprouvé

    Homme Profil pro
    Inscrit en
    Octobre 2003
    Messages
    908
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 908
    Par défaut
    C'est meme beaucoup mieux que de faire avec un entier !

    Le sémaphore est "spécialisé" pour la gestion de ressource.

  8. #8
    Membre Expert
    Avatar de Sub0
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2002
    Messages
    3 573
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 573
    Par défaut
    Merci pour vos réponses. Je progresse grâce à vous !

    En fait, je pense que ce ne sont pas aux threads d'aller vérifier si il ya des fichiers à transférer. Selon moi, c'est au thread principal à distribuer les fichiers aux threads libres. Si vous pensez le contraire, merci d'argumenter un peu.

    Eric Boisvert: Comme je l'ai dis à ShaiLeTroll dans mon 2ème message, je ne compte pas utiliser une TThreadList car j'ai déjà mis au point le fonctionnement des threads qui est assez "complexe" en fait (timeout, reprise du transfert, affichage des messages non répétitifs, etc...), je n'ai pas envie de reprendre cette partie du code. Le tableau de Threads fonctionne parfaitement; Un thread est libre lorsqu'il est suspendu, c'est tout ce que j'ai besoin de savoir. La gestion de la liste des fichiers et la distribution me semble devoir être à part, et fonctionner dans le thread principal du programme.

    Je suis en train d'étudier les sémaphores pour voir si ils peuvent vraiment apporter un plus par rapport à une programmation basique, par exemple avec un timer et une recherche des threads libres, genre :
    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
    Procedure TForm1.AjoutButtonClick(Sender: TObject);
    Begin
      If (OpenDialog1.Execute) Then
        ListFichier.Add(OpenDialog1.Files);
      Timer1.Enabled := (ListFichier.Count > 0);
    End;
     
     
    Procedure TForm1.Timer1Timer(sender: TObject);
    Begin
      Timer1.Enabled := False;
     
      // Distribution des fichiers aux threads libres
      For i := Low(HttpThreads) To High(HttpThreads) Do
        With HttpThreads[i] Do
          If (Suspended) Then Begin
     
            // Thread libre 
            Resume;
            ...
          End;
     
      Timer1.Enabled := (ListFichier.Count > 0);
    End;
    Par contre, il ne faut pas que cette fonction bloque le programme, l'utilisateur doit pouvoir ajouter des fichiers dans la liste ou effectuer d'autres opérations...

  9. #9
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2003
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2003
    Messages : 582
    Par défaut
    Citation Envoyé par Sub0
    Eric Boisvert: Comme je l'ai dis à ShaiLeTroll dans mon 2ème message, je ne compte pas utiliser une TThreadList car j'ai déjà mis au point le fonctionnement des threads qui est assez "complexe" ...
    Désolé d'insister Sub0, mais vais quand même te montrer ou je vois l'utilité
    d'un TThreadList.

    Dans la solution que tu propose, Ce qui me chagrine un peu, c'est le besoin
    d'utiliser un timer, et l'obligation de chercher un thread libre..etc..

    tandis qu'avec l'utilisation d'une TThreadList pour maintenir
    une liste de fichier, avec l'ajout d'un Event....
    ca peut prendre l'allure suivante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
                                    |Thread
                                    |Copie
                                    |File #1
                                   /
      Thread        TThreadList   / |Thread
    Principale   =>    de       =>--|Copie
    Application      fichier      \ |File #2
                     (Fifo)        \
                  (thread-safe)     |Thread
                                    |Copie
                                    |File #X
    dans la ThreadList de fichier on utilisera un Event pour réveiller nos thread de
    copie.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    NewData:THandle;  //Event qui reveillera un de nos thread de copie
    NewData:=CreateEvent(null,FALSE,FALSE,'EventListeFichierNewData');
     
    //lorsqu'il y a un push, on fait un
    SetEvent(NewData);
    //ca va reveiller un des Thread de copie
    ensuite, la boucle pricipale du thead de copie peut ressembler à ca:
    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
     
    //boucle pricipale du thead de copie
    Procedure TMyThreadCopie.Execute;
    Begin
      FreeOnTerminate:=TRUE;
      Repeat
        FileObject=MyThreadListFile.Pop;
        while (FileObject<>nil) and (not Terminated) do
        begin
          //Copy a FileObject....
          //(ton code existant quoi?)
          FileObject=MyThreadListFile.Pop; //Get Next File to copy
        end;
        //ici on attend des nouvelles données cette boucle prend 0% cpu!
        while (WaitForSingleObject(MyThreadListFile.NewData,1000)=WAIT_TIMEOUT do
        begin
            if Terminated then break;
        end;
      Until (Terminated);
    End;
    Comme tu vois, les thread de copie vont pratiquement dormire jusqu'à
    l'arrivé d'une nouvelle donnée dans la liste de fichier.

    Du côté de l'application, on fait des push de fichier n'importe quand...
    Bon c'est plutôt classique comme approche?

    Et finalement, c'est peut-être complètement à côté de ce que tu désire faire...
    Comment dupliquer un disque...ça vous intéresse?
    Tutoriel et code source delphi ici

  10. #10
    Membre Expert
    Avatar de Sub0
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2002
    Messages
    3 573
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 573
    Par défaut
    Citation Envoyé par Eric Boisvert
    Dans la solution que tu propose, Ce qui me chagrine un peu, c'est le besoin d'utiliser un timer, et l'obligation de chercher un thread libre..etc.
    Moi aussi. Je trouve l'utilisation d'un timer inapproprié. C'est pour cette raison que j'ai demandé votre aide. Tu m'as convaincu, je vais étudier la question de la TThreadList.

    Simplement, il faut que vous sachiez que je ne termine pas les threads, je les suspend parce que la création d'un thread crée aussi l'objet Http et que les requêtes Http sont nécessaires pendant toute l'exécution du programme (d'autres fonctions que la copie peuvent être demandées). L'evénement de fin de requête met en pause le thread jusqu'à qu'une nouvelle requête le redémarre. Par exemple, si l'application n'utilise que 2 threads, seulement 2 threads seront créés et si elle utilise les 10, les 10 seront créés et détruis à la fermeture du programme via FreeOnTerminate := True;

    Ça peut vous sembler bizarre, mais je n'ai pas vraiment besoin de détruire l'objet thread et son objet Http pour devoir le recréer...Cela consomme un peu plus de mémoire, certe, mais en contre partie, je gagne du temps en évitant la destruction et recréation de l'objet. C'est peut-être aussi l'avantage d'utiliser une TThreadList : On ne détruit pas le thread jusqu'à qu'on en ait plus besoin, non?

    Mais dans tous les cas, nous sommes bien d'accord sur un point : Ce sera le thread principal qui se chargera de distribuer les fichiers de la liste aux threads de copie libres. TThreadList me semble être une solution très intérressante et performante, mais puis-je l'utiliser sachant que je ne détruis pas les threads ? Le sémaphore ne serait-il pas un choix plus judicieux ?

  11. #11
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2003
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2003
    Messages : 582
    Par défaut
    Citation Envoyé par Sub0
    si l'application n'utilise que 2 threads, seulement 2 threads seront créés et si elle utilise les 10, les 10 seront créés et détruis à la fermeture du programme via FreeOnTerminate := True;
    C'est exactement ce que je voyais
    Citation Envoyé par Sub0
    TThreadList me semble être une solution très intérressante et performante, mais puis-je l'utiliser sachant que je ne détruis pas les threads ?
    Absolument.
    Citation Envoyé par Sub0
    il faut que vous sachiez que je ne termine pas les threads, je les suspend
    Alors là, faudrait pas les suspendre.. c'est eux-mêmes qui vont hiberné en
    attendant quelque chose à faire...avec ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
        //ici on attend des nouvelles données cette boucle prend 0% cpu!
        while (WaitForSingleObject(MyThreadListFile.NewData,1000)=WAIT_TIMEOUT do
        begin
            if Terminated then break;
        end;
    Citation Envoyé par Sub0
    Ce sera le thread principal qui se chargera de distribuer les fichiers de la liste aux threads de copie libres
    Si tu utilise la mon charabia, je dirais non. C'est plutôt la TThreadList qui réveillera les Thread de copie...et eux.. qui vont ce chercher du travail à faire...et en cas de... rien à faire... on attend...

    De mémoire, cette facon de dormir ressemble drôlement à une bonne vieille
    boucle de message windows finalement...
    Comment dupliquer un disque...ça vous intéresse?
    Tutoriel et code source delphi ici

  12. #12
    Membre Expert
    Avatar de Sub0
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2002
    Messages
    3 573
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 573
    Par défaut
    Alors là, faudrait pas les suspendre.. c'est eux-mêmes qui vont hiberné en
    attendant quelque chose à faire...
    Un détail peut-être important pour le choix de la solution appropriée : L'upload Http ne peut-être réalisé en une seule fois, à cause de la limitation de 2Mo du serveur. Aussi, le fichier à copier est ouvert dans un TStream, et envoyé par blocs de 2Mo. En résumé, un thread pour une requête, plusieurs requêtes pour un fichier, plusieurs fichiers dans la liste... Mais je ne pense pas que ça change grand chose, le principe reste le même : Il s'agit de transférer des données, mêmes si le fichier est envoyé en plusieurs fois.

  13. #13
    Membre Expert
    Avatar de Sub0
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2002
    Messages
    3 573
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 573
    Par défaut
    Arf! Que ce soit avec le sémaphore ou la TThreadList, je ne vois pas comment je peux l'intégrer dans mon code. J'ai beau lire l'article de la Faq concernant le sémaphore ou étudier le code d'Eric, je n'y pige rien.

    J'ai déjà réalisé une fonction de copie avec Blockread/BlockWrite et qui affiche la progression et le temps restant :
    http://sub0.developpez.com/delphi/mycopy.zip

    Comment dois-je faire pour préparer une dizaine de thread et afficher la progression et le temps restant pour l'ensemble des copies lancées ?
    Et comment utiliser la TThreadList pour distribuer les fichiers ?
    J'ai pas le niveau...

  14. #14
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2003
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2003
    Messages : 582
    Par défaut
    Voilà Sub0,
    Ma démo pour Copier des fichiers en multi-thread, avec feed back, etc...

    Tu remarquera que j'utilise en faite 2 TThreadList (Fifo Thread-Safe)
    Une pour la liste des fichiers à copier
    une pour le feedback...

    ca devrait te permettre de créer une adaptation pour ton prog...

    Bonne Chance!

    PS: Je vais bientôt manquer de place... j'atteind presque ma l'imite de fichier
    attaché....quelqu'un peut-il arranger ca?
    Comment dupliquer un disque...ça vous intéresse?
    Tutoriel et code source delphi ici

  15. #15
    Membre Expert
    Avatar de Sub0
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2002
    Messages
    3 573
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 573
    Par défaut
    Un grand merci à toi Eric! J'en espèrais pas tant.
    Cet aprèm, j'ai travaillé dessus et j'ai finalement vraiment simplifié les choses :
    • Pas de timer cette fois-ci, juste une TStringList dans laquelle j'ajoute les fichiers
    • Tout de suite après ce OpenDialog, je lance les threads de copie jusqu'à que tous les threads libres soient pris ou qu'il n'y ait plus de fichiers dans la liste
    • Je met une chaîne vide à la place du nom de fichier pour signifier que sa copie est effectuée
    • Lorsqu'un thread a terminé la copie, il regarde si il reste des fichiers à copier
    • Lorsqu'il n'y a plus de fichier à copier, je vide la liste

    Mais maintenant, avec ta démo, je pense que je pourrais y arriver.

    ps: Veux-tu proposer ton code pour la page source de Delphi ?

  16. #16
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2003
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2003
    Messages : 582
    Par défaut
    Et comment fais-tu ton Feed-Back de la copie avec le thread Principal?
    Synchronize? C'est pas évidant de travailler avec ca non?


    Citation Envoyé par Sub0
    Mais maintenant, avec ta démo, je pense que je pourrais y arriver.
    Ca j'en suis certain! Jette un coup d'oeil... c'est pas si sorcier...

    Citation Envoyé par Sub0
    ps: Veux-tu proposer ton code pour la page source de Delphi ?
    Je veux bien... mais faudrait la documenter un peu mieux...
    Comment je procède pour la soumettre?

    Citation Envoyé par Eric Boisvert
    PS: Je vais bientôt manquer de place... j'atteind presque ma l'imite de fichier
    attaché....quelqu'un peut-il arranger ca?
    Est-ce que tu sais si il y a quelque chose à faire pour ca?
    Comment dupliquer un disque...ça vous intéresse?
    Tutoriel et code source delphi ici

  17. #17
    Membre Expert
    Avatar de Sub0
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2002
    Messages
    3 573
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 573
    Par défaut
    Citation Envoyé par Eric Boisvert
    Et comment fais-tu ton Feed-Back de la copie avec le thread Principal?
    J'avoue, j'ai pas encore bien saisi ce qu'était un Feed-back. Je vais tout de même essayer de te répondre; La copie est une boucle qui se trouve dans la procédure Execute du thread. A chaque itération, j'envoi un bloc de données de 2Mo max au serveur. L'objet Http possède un evénement OnRequestDone dans lequel je vérifie la réception des données. Là aussi, j'affiche la progression et je peux décider de poursuivre la copie ou d'en reprendre une nouvelle... Cela répond-t-il à ta question ou je suis hors sujet ?

    Citation Envoyé par Eric Boisvert
    Synchronize?
    Synchronize me sert à faire une pause dans le thread, le temps d'afficher la progression, un message d'erreur ou poser la question d'écrasement de fichiers...

    Citation Envoyé par Eric Boisvert
    C'est pas évidant de travailler avec ca non?
    Faut aussi avouer que dans l'ensemble, les threads, la TThreadList ou le sémaphore ne sont pas évidents non plus...
    Mais bon, j'imagine que tu connais mieux que moi le sujet.

    Citation Envoyé par Eric Boisvert
    Ca j'en suis certain! Jette un coup d'oeil... c'est pas si sorcier...
    Ça fait beaucoups de code qu'en même et j'ai encore du mal à saisir certaines choses... Je cherche également à bien comprendre les avantages du concept par rapport à la méthode que j'ai utilisé cet aprem. En tous les cas, ça marche plutôt bien la TThreadList.

    Citation Envoyé par Eric Boisvert
    Je veux bien... mais faudrait la documenter un peu mieux...
    Comment je procède pour la soumettre?
    En effet, il faudrait, pour bien faire, commenter un peu plus et en Français. Je pense aussi qu'il faudrait coder la copie dans une boucle avec TFileStream ou BlockRead/BlockWrite. Sinon, rien à redire sur cette démo. Je pense que c'est un bon cas d'école. Pour la soumettre, poste un nouveau sujet dans le sous-forum FAQ/Sources de Delphi.


    Citation Envoyé par Eric Boisvert
    Est-ce que tu sais si il y a quelque chose à faire pour ca?
    Je ne savais même pas qu'il y avait une limitation sur les pièces jointes. Je les utilise très rarement, je préfère de loin mettre mes archives sur mon site et donner un lien. De cette manière, je peux toujours modifier le code sans devoir éditer le message si je m'apperçois d'une erreur ou d'un bug. Je peux aussi le donner dans d'autres posts sans l'attacher à nouveau. Peut-être devrais-tu voir ce sujet :

    http://developpez.net/forums/showthread.php?t=157450

  18. #18
    Membre Expert
    Avatar de Sub0
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2002
    Messages
    3 573
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 573
    Par défaut
    J'ai codé une démo avec la méthode que j'ai utilisé cet aprem en essayant de refaire le même programme que toi sauf que j'ai ajouté la copie dans une boucle (TFileStream). Le programme fonctionne chez moi sauf qu'il ne faut pas oublier de désactiver le déboggage intégré pour que les exceptions fonctionnent correctement si on lance l'exécution à partir de l'EDI. Bref, tu remarqueras surtout la taille du code...

    Citation Envoyé par Eric Boisvert
    C'est pas évidant de travailler avec ca non?
    A toi de juger à présent.
    J'attend avec impatience tes impressions.

    http://sub0.developpez.com/delphi/threadscopy.zip

  19. #19
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2003
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2003
    Messages : 582
    Par défaut
    Citation Envoyé par Sub0
    J'avoue, j'ai pas encore bien saisi ce qu'était un Feed-back.
    Juste en passant, j'utilise le mot Feedback ce qui correspond selon moi à donner la progression à l'usager.
    (c'est une traduction libre biensûr!)


    Citation Envoyé par Sub0
    J'attend avec impatience tes impressions.
    Et bien les voilà:

    1- La destruction des Threads en mode automatique (FreeOnTerminate := True) peut ce faire à la seule condition
    que le thread puissent sortir de la boucle Execute. On a donc un petit problème ici à corriger.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    Procedure TForm1.FormCloseQuery(Sender: TObject; Var CanClose: Boolean);
    Var i: Integer;
    Begin
      For i := 0 To NbrThreads - 1 Do Begin
        //MyThreads[i].Suspend;   // à enlever pour les raisons suivante: 
        MyThreads[i].Terminate; //Le thread est suspendu donc appeler Terminate
                                //ne servait à rien et le thread n'était pas détruit.
        MyThreads[i].Suspended := False; //Active le thread (on doit le laisser terminer!)
        MyThreads[i].WaitFor;   //Attend la sortie du Thread
      End;
     
      CanClose := True;
    End;
    2- Si on quitte pendant une copie en cours, la boucle de copie ne verifie pas si Terminated=TRUE.
    On devra alors attendre la fin de la copie avant de quitter l'application...
    Et c'est probablement pas ce que l'on souhaite!
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    //Dans Procedure TMyThread.Execute;
    Repeat
      p := s.Position;
      s.Read(Buf, Length(Buf));
      d.Write(Buf, s.Position - p);
      Synchronize(UpdateView);
      if Terminated then break; //(À Ajouter) Si Terminate, on doit Quitter!
    Until (d.Size >= s.Size) Or (s.Position - p <> Length(Buf));]
    3- Lorsque tu ajoute des fichiers dans la liste, tu n'a pas besoin d'arrêter les threads en cours
    car la selection de nouveau fichier se fait à l'aide de Synchronize. Donc impossible que tu
    soit en ajout de fichier pendant qu'un thread en prend un.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    //dans TForm1.AjouterClick(Sender: TObject);
    //{ Pause des threads }
    //  For i := 0 To NbrThreads - 1 Do
    //    MyThreads[i].Suspended := True;	
    // Inutile car les threads sont en synchronize pour piger dans la liste!
    4- Le fait d'utiliser Synchronize, (preuve pour #3 aussi) détruit un peu le multi-Thread.
    Un simple F1 sur Synchronize t'expliquera d'avantage que moi la source du problème...
    Pour en faire la preuve, réduit à 2 thread ton application, et effectue une copie de 3-4 gros fichiers et pendant le download en cours, appuie sur ce bouton qui inclus ce code bidon:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    procedure TForm1.Button1Click(Sender: TObject);
    var
        i:integer;
    begin
        //Simulation d'un Long calcules de 30 sec.
        Application.
        for i:=0 to 3000 do
        begin
            sleep(10);
        end;
    end;
    Et oui , les threads ont arrêté de copier...Ils étaient en arrêt dans Synchronize(UpdateView)
    car ton application principale était occupée...
    Il est claire qu'ici, ce n'est peut-être pas un gros problème...Le synchronise
    devient pratique
    surtout lorsque le thread veut absolument une réponse de l'usager par exemple...
    Dans d'autre cas, on ne voudrait absolument pas ralentire un gros calcule
    par exemple pour des raisons de feedback...C'est bien là que la Fifo Thread-Safe intervient.

    Citation Envoyé par Sub0
    Bref, tu remarqueras surtout la taille du code...
    C'est Simple, court et éfficace dans ce contexte. C'est du Sub0 quoi!


    Bref...C'était bien intéressant tout ca...

    Je serais bien curieux de voir l'attaque de ce problème avec les Semaphores...
    Si quelqu'un les connait bien...ce serait intéressant de voir de quelle façon
    une démo semblable à la nôtre peut-être écrite en les utilisant?
    Comment dupliquer un disque...ça vous intéresse?
    Tutoriel et code source delphi ici

  20. #20
    Membre Expert
    Avatar de Sub0
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2002
    Messages
    3 573
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 573
    Par défaut
    Tes remarques sont très intérressantes. Juste rencontré un ptit problème : J'ai modifié le code comme tu me l'as dis pour le OnCloseQuery, et j'ai un bug : Exception EOSError code 6 sur le WaitFor j'ai l'impression...

Discussions similaires

  1. Copie d'un fichier avec des caractères spéciaux
    Par totofe dans le forum Scripts/Batch
    Réponses: 5
    Dernier message: 15/09/2010, 12h28
  2. Liste de fichiers avec liens et classement
    Par illidan05 dans le forum Excel
    Réponses: 1
    Dernier message: 21/05/2008, 14h48
  3. recuperer liste de fichier avec http
    Par etoileDesNeiges dans le forum Entrée/Sortie
    Réponses: 3
    Dernier message: 10/04/2007, 12h02
  4. Réponses: 16
    Dernier message: 07/04/2005, 11h36

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