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

Python Discussion :

Creer un grand nombre de fichier rapidement


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 12
    Par défaut Creer un grand nombre de fichier rapidement
    Bonjour,

    Je suis confronté à un problème bête mais pour lequel je ne trouve pas de solution.
    [contexte]
    J'ai crée un programme python tournant avec mpi pour tester plusieurs logiciels dans le domaine de la bioinfo. Concrètement, il lance plusieurs logiciels avec différents paramètres et fichiers en entrée.
    [Problème]
    Et donc le problème est la création des fichiers d'entrée. Je dois créer 156408 fichiers "couples" qui contiennent à chaque fois la concaténation de deux autres fichiers.
    donc c'est très bêtes en utilisant 2 "cat " on peut créer un fichier. Mais c'est très long.
    Donc j'ai essayé de paralléliser les choses pour profiter d'un nas avec une partition de type lustre [URL="http://en.wikipedia.org/wiki/Lustre_%28file_system%29"] que j'ai à disposition mais il n'y a pas de gains.
    J'ai essayé de n'utiliser que du code python comme ce qui suit :
    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
     
        def createCouple(self, sRNA, mRNA):
            """
            Create the couple
            @param sRNA: name of the sRNA file
            @param mRNA: name of the mRNA file
            """
            #Definition du fichier
            out=self.sRNA_out+"couple_"+sRNA+"_"+mRNA+".fasta"
            try:
                #Creation du fichier et copie du contenu du premier fichier
                shutil.copy(self.sRNA_out+sRNA+".fasta",out)
                #Ajout du contenu du deuxieme fichier
                outfile=open(out,"a")
                outfile.write(open(self.mRNA_out+mRNA+".fasta","r").read())
                outfile.close()
            except IOError:
                sys.exit("Execution failed with %s"%out)
            except:
                sys.exit("There is something wrong with the copy of %s"%out)
    Voilà, donc j'aimerais bien trouver une solution qui me permette de créer instantanément ces fichiers et ne pas passez plusieurs heures sur cette étape (que je dois répéter en plus assez régulièrement).

    Voici le contenu typique d'un seul fichier :
    >NC_000913_CyaR
    gctgaaaaacataacccataaaatgctagctgtaccaggaaccacctccttagcctgtgtaatctcccttacacgggcttatttttt
    donc chaque fichier contient très peu de données. Et bien sûr, je ne peux pas faire un seul fichier qui contient toutes les données.

  2. #2
    Membre Expert

    Homme Profil pro
    Diverses et multiples
    Inscrit en
    Mai 2008
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Diverses et multiples

    Informations forums :
    Inscription : Mai 2008
    Messages : 662
    Par défaut
    Je n’ai aucune idée des perfs de lustre, mais s’il supporte vraiment bien des opérations massivement parallèles, ça devrait quand même accélérer les choses…

    Sous python, tu as
    *threading, mais le GIL à pour effet de sérialiser l’exécution des threads python, donc ce n’est pas du vrai parallélisme (même si ça devrait quand te permettre de gagner en “effaçant” une bonne partie des latences des opérations sur le fichiers).
    *multiprocessing, qui permet de paralléliser en lançant de vrais processus.
    *concurrent.futures (python3.2 uniquement), qui regroupe les deux précédents sous une même interface.

    Donc, en lançant plusieurs dizaine (ou centaines, suivant ta mémoire dispo, et les caractéristiques de lustre) de processus qui exécutent ta fonction de concaténation, tu devrais quand même gagner du temps.

    Par contre, faut pas rêver, concaténer plus de cent mille fichiers ne se fera jamais instantanément…

    Au fait, tu devrais aussi tester si shutil.copy est bien plus efficace qu’une lecture-écriture de fichier, surtout sur des volumes de données aussi faibles…

  3. #3
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Bonjour,

    Je me plante sans doute mais:
    On est bien d'accord sur le fait que le goulot le plus important lors de l'utilisation de fichiers (surtout ici vu la taille des fichiers) est la lecture/écriture disque... et shutil.copy fait une lecture du fichier pour le réécrire (+ chmod au passage).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    def copyfileobj(fsrc, fdst, length=16*1024):
        """copy data from file-like object fsrc to file-like object fdst"""
        while 1:
            buf = fsrc.read(length)
            if not buf:
                break
            fdst.write(buf)
    Que donne l'ouverture des deux fichiers (with open(file, mode)) en lecture et l'écriture le fichier concaténé en mémoire au niveau performance ?

    @+

  4. #4
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Pourquoi ne pas utiliser le système (cat src1.txt src2.txt > result.txt) et paralléliser, comme le dit mont29, plusieurs processus sans en attendre la fin ?

    @+

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 12
    Par défaut
    Merci de vos réponses, je vais tester ta première solution PauseKawa et je vais aussi comparer par rapport à un petit programme C que j'ai crée pour l'occasion. C'est sûr que si une solution python presque aussi efficace qu'en C marchait, ça serait parfait


    Sous python, tu as
    *threading, mais le GIL à pour effet de sérialiser l’exécution des threads python, donc ce n’est pas du vrai parallélisme (même si ça devrait quand te permettre de gagner en “effaçant” une bonne partie des latences des opérations sur le fichiers).
    *multiprocessing, qui permet de paralléliser en lançant de vrais processus.
    *concurrent.futures (python3.2 uniquement), qui regroupe les deux précédents sous une même interface.
    Pour paralléliser, j'utilise mpi4py, pas le choix sur le cluster de calcul que j'utilise.
    Et malheureusement, la parallélisation a ses défauts qui joue peut être ici, à savoir les communications même si je les ai réduit au maximum. (Et pas de python 3.2 sur le cluster mais merci pour le lien).

    Et j'y pense, en y réfléchissant, que le goulot peut venir du fait que je n'ai fait qu'écrire dans la partition lustre. Le goulot venait peut être de la lecture qui était sur une partition classique. à tester...

    Pourquoi ne pas utiliser le système (cat src1.txt src2.txt > result.txt) et paralléliser, comme le dit mont29, plusieurs processus sans en attendre la fin ?
    C'était ma première solution mais elle n'est pas plus efficace et en plus requiert que le système soit un linux.

  6. #6
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Citation Envoyé par exeroc Voir le message
    C'était ma première solution mais elle n'est pas plus efficace et en plus requiert que le système soit un linux.
    Que nenni
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    type src1 src2 > result
    copy /b src1+src2 result
    Par contre je recarderais effectivement au niveau du lecteur source comme tu le dit.

    @+

  7. #7
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 762
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 762
    Par défaut
    Salut

    La gestion des fichiers se décompose en:
    • creation de l'entrée dans le répertoire,
    • allocation des blocks lorsqu'on écrit dedans.


    Ces deux opérations sont plutôt sérialisées: si deux process peuvent créer des fichiers "en même" temps, le file system fera ces deux opérations de façon séquentielle et avec des IO plus ou moins asynchrone pour en garantir l'atomicité.

    Toutes ces opérations induisent de petites IOs alors que vous utiliserez au mieux la bande passante disque en faisant de grosses IOs.

    Lustre n'apporte rien car s'il est fait pour gérer des milliards de fichiers et des Exabytes les opérations élémentaires restent "bornées" par l'atomicité et la séquentialité nécessaire aux opérations précédentes.
    Note: ne pas confondre bande passante qui est un débit et la vitesse. Ce n'est pas parce que Lustre (ou un camion) supporte plus de requêtes/s. (marchandise) qu'il ira plus "vite" (qu'une ferrari).

    Le sous système IO est à priori le bottleneck mais créer 200000 process pour réaliser ces opérations élémentaires n'est pas une bonne chose non plus car ils ne dureront pas assez longtemps pour compenser l'overhead de leur création/destruction.

    On fait quoi?
    • Quelles sont vos attentes?
    • Quel genre de techno il va falloir mettre sous le capot pour y arriver?
    • Comment on la met en oeuvre?


    J'ignore vos attentes mais on peut mettre des nombres pour avoir une idée... ce qui permettra de toucher les réalités "physiques" de cela.
    La création de 200.000 fichiers de 100 octets, c'est de l'ordre du million d'IO.
    Si le sous système IO à un débit de 1000 IO/s (ou 1ms/IO) c'est 1000 seconds ou ~20Mns.

    => Si vous voulez que ca dure 1Mn il faudra "distribuer" 5000 IO/s sur plus d'une 20aine de disques. Pour réaliser cela de façon "transparente" côté programme, il faut des technologies de virtualisation côté baie de stockage (et/ou un contrôleur intelligent)

    Ceci dit on parle de 200.000 fichiers d'environ 100c çà fait 20Mo... ce qui est peanuts côté "mémoire" et un ramdisk devrait aider un peu - si vous ne prenez pas un driver trop pourri sinon il y a aussi des disques SSD.

    En supposant que ces technos permettent d'aller 100 fois plus vite, nous pouvons espérer faire ce million d'IO en 10 secondes ou 100000 opération/secondes.

    Le code: la question est "sur quoi agir pour aller vite".

    Si on garde le design de createCouple, il va falloir l'exécuter 200000 fois sur des fichiers "à priori" différents et "vite" => distribuer ces 200.000 opérations sur l'ensemble des CPU disponibles pour que le débit soit le meilleur possible.

    Il faut répartir le boulot (la charge) sur les 4 CPUs: imaginez la création de 4 process en leur passant des paramètres pour désigner les 50000 opérations qu'ils doivent faire.

    Il faut occuper les CPUs: çà fait des IOs, donc çà attend, donc on peut en poster plus...donc threads.
    note: attention quand même les IO disques on attend le disque, avec le RAM disk on attend la mémoire...

    Mais est-il raisonnable de créer 50000 threads?
    La capacité du CPU limitera le nombre de threads "actives" à 2, 5, ... 10, 100?
    En gros, on va en avoir 49900 qui glandouillent mais leur création c'est 49900 opérations qui n'améliorent pas le débit (donc qui coûtent pour rien).

    Pour s'en sortir on "chunke": chaque thread effectue un certain nombre d'opérations (comme on sait combien il y a de fichiers à traiter...).

    Dans la pratique, ca donne un script qui se lance à la console avec les paramètres N1, N2, chunk_size ou N1 et N2 définissent l'intervalle des fichiers à traiter et chunk_size le nombre de fichiers traités par threads.

    Une fois trouvé le chunk "optimal"... On espère qu'en lançant autant de traitement que de CPU, la durée sera "identique" : ça traitera 4 fois plus de fichiers "aussi vite" parce qu'on a mis 4 fois plus de CPU au boulot.
    Si ca ne le fait pas, c'est qu'il y a des "bootleneck" côté mémoire ou driver RAM disk - ou un gros bug dans le code.

    Ca c'est le plan... pour tester la capacité de la bête, on ne va peut être pas s'embarquer immédiatement à rédesigner peu ou prou le truc pour qu'il puisse être "partitionnable à souhait": après tout, on ne veut que mesurer la durée de lecture et écriture de 'beaucoup" de petits fichiers.

    Poser N fichiers dans un répertoire et avoir une activité qui copie les fichiers dont le numéro est dans un intervalle(x, x+chunk) dans un autre répertoire devrait être "suffisant" et rapide à réaliser.

    Ensuite paralléliser avec concurrent.futures/threads (cité par PauseKawa) qui est aussi dispo en 2.6 et plus via un kit. C'est facile à mettre en oeuvre.
    Et leur faire bouffer les processeurs via os.popen, c'est pas trop compliqué.

    Avec cela vous avez construit une jauge permettant de voir le débit que vous pouvez obtenir avec le RAM disk, la bande passante mémoire, les CPU disponibles.

    En rangeant bien nous avons simplifié la distribution des traitements... ce n'est peut être pas applicable dans votre cas mais la jauge vous dira ce que vous gagneriez à améliorer l'algorithme de distribution .

    Cordialement,
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 12
    Par défaut
    Bonjour,

    Je vous remercie de ces réponses.
    wiztricks : Je ne vois pas encore comment implémenter ta proposition mais les résultats de mon programme de test en C sont si édifiants que je pense m'en arrêter là.

    J'ai réimplémenté le petit algo énoncé en début en C (petit moment douloureux - je n'en avais pas fait depuis près d'un an). On passe de 50 à 300 lignes de codes et surtout pas de parallélisation dans le code c. Je suis allé au plus simple pour avoir des résultats le plus rapidement possible.

    Niveau architecture Intel(R) Xeon(R) CPU E5540 @ 2.53GHz (un seul cpu du cluster).
    Il y avait 156408 fichiers à créer, le programme n'est pas à 100% optimisé, j'ai compilé avec gcc -O3 et j'ai lancé sur une partition linux classique, voilà les temps :
    real 5m38.987s
    user 0m3.044s
    sys 0m27.954s
    La consommation d'un seul des cores du CPU a oscillé entre 3 et 8%. et surtout on passe de plusieurs heures en python à 5 min et les fichiers sont effectivement correct.
    Je dois dire que je ne comprends où est le problème avec mon premier algo en python et sans parallélisation (c'était une bête boucle qui lançait deux cats). Peut être que ta solution PauseKawa est plus rapide.
    Mais je pense que le mieux, maintenant, est peut être d'inclure ce code C dans le programme python principal. Savez vous s'il y a des risques de perte de performance ?

    En tout cas, je n'en reviens pas de cette différence...

  9. #9
    Membre Expert

    Homme Profil pro
    Diverses et multiples
    Inscrit en
    Mai 2008
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Diverses et multiples

    Informations forums :
    Inscription : Mai 2008
    Messages : 662
    Par défaut
    Bon, alors, je viens de faire un petit test, en créant deux fois 100000 fichiers sur ma modeste ext4 sur HDD de portable 5400rpm, puis en concaténant les paires dans une troisième série de fichiers. Verdict*: 30 à 40 secondes*!

    Je ne comprends pas d’où vient ton problème… Ici, j’ai utilisé les os.open/read/write, qui utilisent des descripteurs de fichiers (api bas niveau), mais même avec open() je reste sous la minute (voire plus bas)…

    Mon code (py3, mais il devrait aussi fonctionner sous py2, à quelques adaptations près)*:

    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
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
     
    import os, time
     
    dir_in1 = "/home/i7deb64/Bureau/test/di1"
    dir_in2 = "/home/i7deb64/Bureau/test/di2"
    dir_out = "/home/i7deb64/Bureau/test/do"
     
    NR = 100000
    MAX_LEN = 8096
     
    for i in range(NR):
    	try:
    		fi1 = os.open("/".join((dir_in1, str(i))), os.O_WRONLY | os.O_CREAT)
    		fi2 = os.open("/".join((dir_in2, str(i))), os.O_WRONLY | os.O_CREAT)
    		os.write(fi1, b"gctgaaaaacataacccataaaatgctagctgtaccaggaaccacctccttagcctgtgtaatctcccttacacgggcttatttttt")
    		os.write(fi2, b"Lorem ipsum")
    	finally:
    		os.close(fi1)
    		os.close(fi2)
     
    tm = time.time()
    for i in range(NR):
    	try:
    		fi1 = os.open("/".join((dir_in1, str(i))), os.O_RDONLY)
    		fi2 = os.open("/".join((dir_in2, str(i))), os.O_RDONLY)
    		fo  = os.open("/".join((dir_out, str(i))), os.O_WRONLY | os.O_CREAT)
    		os.write(fo, b"".join((os.read(fi1, MAX_LEN), os.read(fi2, MAX_LEN))))
    	finally:
    		os.close(fi1)
    		os.close(fi2)
    		os.close(fo)
     
    exec_time = time.time() - tm
     
    print("concat time: {} seconds".format(exec_time))
    Notes*:
    # Tous les fichiers ont le même contenu, mais je doute que ça joue beaucoup sur le perfs, ici…
    # J’ai simplifié les choses, en donnant une taille maximales aux données des fichiers à concaténer (ici, 8096 octets)…
    # os.read/os.write ne manipulent que des bytes (mais en py2, ça n’a pas trop d’importance, en fait…).
    # Avec pas mal de mémoire vive, ça peut aller encore bien plus vite, Linux cachant les opérations sur disque (pour info, avec 10000 opérations, ça dure 0.5 secondes sur ma machine*!).

    Pour info, si l’on remplace le code de concaténation des fichiers par*:

    [code] with open("/".join((dir_in1, str(i))), "r") as fi1, open("/".join((dir_in2, str(i))), "r") as fi2, open("/".join((dir_out, str(i))), "w") as fo:
    fo.write("".join((fi1.read(), fi2.read())))[code]

    …On monte à 1.5, 3 secondes pour 10000 opérations, et entre 40 et 50 secondes pour 100000 opérations…

  10. #10
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Bonjour,

    Citation Envoyé par exeroc Voir le message
    et surtout on passe de plusieurs heures en python à 5 min et les fichiers sont effectivement correct.
    Je veux bien que Python ne soit pas le plus rapide mais là il y a souci.
    Peut être dans ce qui suit :
    Citation Envoyé par exeroc Voir le message
    Pour paralléliser, j'utilise mpi4py, pas le choix sur le cluster de calcul que j'utilise.
    Et malheureusement, la parallélisation a ses défauts qui joue peut être ici, à savoir les communications même si je les ai réduit au maximum
    Ceci dit, non, il n'y auras pas de perte de performance (sauf erreur humaine).

    Pour ce qui est des outils Python voici un comparatif (sur ton code) à propos de shutil. Je n'y inclus pas subprocess/P_NOWAIT ou un exec car c'est une autre approche (sans barrière).
    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
    #! /usr/bin/env/ python
    # -*- coding: utf-8 -*-
    # 
    #
    from random import randint
    import os
    import time
    import shutil
     
    def testopen(nb, name1, name2, repcible):
        for index in range(0, nb):
            out = open(repcible + 'couple_%s_%d_%s_%d.fasta'% (name1, index, name2, index), 'w')
            src1 = open('%s_%d'% (name1, index), 'r')
            out.write(src1.read())
            src1.close()
            src2 = open('%s_%d'% (name2, index), 'r')
            out.write(src2.read())
            src2.close()
            out.close()
     
    def testwithopen(nb, name1, name2, repcible):
        for index in range(0, nb):
            with open(repcible + 'couple_%s_%d_%s_%d.fasta'% (name1, index, name2, index), 'w') as out:
                with open('%s_%d'% (name1, index), 'r') as src1:
                    with open('%s_%d'% (name2, index), 'r') as src2:
                         out.write(src1.read())
                         out.write(src2.read())
     
    def testshutil(nb, name1, name2, repcible):
        shcp = shutil.copy
        for index in range(0, nb):
            out = repcible + "couple_" + name1 + "_" + str(index) + '_' + name2 + "_" + str(index) + ".fasta"
            shcp(name1+'_'+str(index), out)
            #Ajout du contenu du deuxieme fichier
            outfile = open(out, "a")
            outfile.write(open(name2+'_'+str(index), "r").read())
            outfile.close()
     
    def inittest(nb, tests):
        print('Grand ménage...')
        print('Création des répertoires cibles')
        for name in tests:
            if os.path.isdir(name):
                shutil.rmtree(name)
            os.mkdir(name)
        print('Suppression des fichiers')
        for item in os.listdir(os.getcwd()):
            if item.startswith('src'):
                os.remove(item)
        print('Création de 2 x ' + str(nb) + ' fichiers')
        letters = 'acgt'
        for index in range(0, nb):
            i = 1
            src1 = ''
            src2 = ''
            while i < 88:
                src1 = src1 + letters[randint(0, 3)]
                src2 = src2 + letters[randint(0, 3)]
                i += 1
            # Python 3 >
            # with open('src1_'+str(index), 'w') as f1, open('src2_'+str(index), 'w') as f2:
            with open('src1_'+str(index), 'w') as f1:
                f1.write(src1+'\n')
            with open('src2_'+str(index), 'w') as f2:
                f2.write(src2+'\n')
     
    if __name__ == "__main__":
        nb = 10000
        tests = ['testshutil', 'testopen', 'testwithopen']
        inittest(nb, tests) # < Attention avec cela !
        print('Début des tests')
        print('open:')
        repcible = os.path.join(os.getcwd(), 'testopen') + os.sep
        t1 = time.clock()
        testopen(nb, 'src1', 'src2', repcible)
        t2 = time.clock()
        print(t2-t1)
        print('with open:')
        repcible = os.path.join(os.getcwd(), 'testwithopen') + os.sep
        t1 = time.clock()
        testwithopen(nb, 'src1', 'src2', repcible)
        t2 = time.clock()
        print(t2-t1)
        print('shutil:')
        repcible = os.path.join(os.getcwd(), 'testshutil') + os.sep
        t1 = time.clock()
        testshutil(nb, 'src1', 'src2', repcible)
        t2 = time.clock()
        print(t2-t1)
    Output
    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
    patrice@Zeus:~/Bureau/test$ /usr/bin/python2.6 shearletter.py 
    Grand ménage...
    Création des répertoires cibles
    Suppression des fichiers
    Création de 2 x 10000 fichiers
    Début des tests
    open:
    2.72
    with open:
    2.64
    shutil:
    4.53
    patrice@Zeus:~/Bureau/test$ /usr/bin/python3.1 shearletter.py 
    Grand ménage...
    Création des répertoires cibles
    Suppression des fichiers
    Création de 2 x 10000 fichiers
    Début des tests
    open:
    6.54
    with open:
    6.52
    shutil:
    8.78
    @+

  11. #11
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Je regarderez aussi du coter d'un try/while qui tourne en bourrique : print est ton ami.

    Je ne connais pas mpi4py mais travaille t'il avec des lock comme les threads ?

    @+

  12. #12
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Citation Envoyé par PauseKawa Voir le message
    Pour ce qui est des outils Python voici un comparatif (sur ton code) à propos de shutil.
    A noter que cela ne concerne que la comparaison avec le read/write + chmod de shutil, pas le travail en mémoire que je site plus haut, soit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    def testwithopen(nb, name1, name2, repcible):
        for index in range(0, nb):
            with open(repcible + 'couple_%s_%d_%s_%d.fasta'% (name1, index, name2, index), 'w') as out:
                with open('%s_%d'% (name1, index), 'r') as src1:
                    with open('%s_%d'% (name2, index), 'r') as src2:
                         result = src1.read() + src2.read()
                         out.write(result)

  13. #13
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 12
    Par défaut
    Merci PauseKawa pour ton petit benchmark !

    J'ai repris ta solution 1 (plus adaptée dans mon cas), j'ai viré toute parallélisation et j'ai surtout enlevé une vérification (faites avec une regex) réalisée pour la moitié des fichiers (et que j'avais oublié) et les résultats sont là :
    156408 fichiers à nouveau et :

    real 6m48.276s
    user 0m11.529s
    sys 0m27.426s

    Python fait presque aussi bien que ma version C, c'est vraiment appréciable.
    Donc c'était une grosse erreur de chercher à paralléliser ça, j'aurais mieux fait de réfléchir un peu plus. Le problème est donc résolu

  14. #14
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 762
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 762
    Par défaut
    Salut,
    [QUOTE=exeroc;6123086]wiztricks : Je ne vois pas encore comment implémenter ta proposition mais les résultats de mon programme de test en C sont si édifiants que je pense m'en arrêter là.[QUOTE]

    Comme vous semblez être un peu perdu dans un milieu ou "paralléliser" s'applique à de "gros" calculs, je voulais juste vous donnez des indications sur comment estimer la taille de votre problème et ce qu'il pouvait être envisagé pour aller "plus vite".

    règle.1: établir des ordres de grandeur sur le temps que prendront vos calculs/activités.
    Cela peut être fait "avant" de coder ou "après" i.e. si la durée ne vous convient inutile de changer de technique sans avoir réussi à estimer le "raisonnable".

    règle.2: paralléliser = "changer la distribution des traitements"
    => autres sollicitations des capacités "en jeu" (cpu, memoire, disques,...).
    Exemple:
    real 6m48.276s
    user 0m11.529s
    sys 0m27.426s
    En gros, le traitement dure 400s mais ne consomme que ~40s de CPU.
    => i.e çà attend 90% du temps.
    Aller plus "vite" suppose soumettre plus de requêtes par unité de temps ET... que le sous-système IO soit capable de les absorber => 10X = RAMdisk.

    règle.3: limiter les overheads.
    paralléliser "beaucoup" d'activités élémentaires (ici 150000 * peanuts) passe par la répartition des activités aux ressources (CPU, mémoire). Le support de cette répartition seront des threads et des process dont la gestion "coûte" du CPU et du temps => "chunks".

    Bon courage,
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  15. #15
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 12
    Par défaut
    Très interessant ces petits benchs . Je vais implémenter tes meilleurs solutions.

  16. #16
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Bonjour exeroc,

    Puisque vous aimez bien les tests quelques résultats* suite à ce sujet:
    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
    Grand ménage...
    Création des répertoires cibles
    Suppression des fichiers
    Création de 2 x 10000 fichiers
    Début des tests
    testopen:
    6.23
    10000
    testmp:
    3.16
    10000
    ...
    Grand ménage...
    Création des répertoires cibles
    Suppression des fichiers
    Création de 2 x 100000 fichiers
    Début des tests
    testopen:
    98.39
    100000
    testmp:
    61.07
    100000
    ...
    Grand ménage...
    Création des répertoires cibles
    Suppression des fichiers
    Création de 2 x 10000 fichiers
    Début des tests
    testopen:
    6.39
    10000
    testmp:
    3.21
    10000
    testmpmulti:
    2.19
    10000
    Comme le dit wiztricks à vous d'estimer (dans le "raisonnable" bien sur).

    @+

    *Code pour le sujet.
    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
    137
    138
    139
    #! /usr/bin/env/ python
    # -*- coding: utf-8 -*-
    # 
    #
    from random import randint
    import os
    import time
    import shutil
    from multiprocessing import Process, Value, Manager
    import sys
     
    def testopen(nb, n1, n2, rc):
        op = open
        st = str
        for i in range(0, nb):
            out = op(rc + "couple_" + n1 + "_" + st(i) + '_' + n2 + "_" + st(i) +
                     ".fasta", 'w')
            src1 = op(n1 + '_' + st(i), 'r')
            src2 = op(n2 + '_' + st(i), 'r')
            out.write(src1.read() + src2.read())
            src1.close()
            src2.close()
            out.close()
     
    def testmp(lproxy, nb, n1, n2, rc):
        op = open
        st = str
        while True:
            try:
                val = lproxy.pop()
            except IndexError:
                break
            out = op(rc + "couple_" + n1 + "_" + val + '_' + n2 + "_" + val +
                     ".fasta", 'w')
            src1 = op(n1 + '_' + val, 'r')
            src2 = op(n2 + '_' + val, 'r')
            out.write(src1.read() + src2.read())
            src1.close()
            src2.close()
            out.close()
     
    def testmpmulti(lproxy, endtime, tclock, nb, n1, n2, rc):
        op = open
        st = str
        while True:
            try:
                val = lproxy.pop()
            except IndexError:
                endtime.append(tclock())
                break
            out = op(rc + "couple_" + n1 + "_" + val + '_' + n2 + "_" + val +
                     ".fasta", 'w')
            src1 = op(n1 + '_' + val, 'r')
            src2 = op(n2 + '_' + val, 'r')
            out.write(src1.read() + src2.read())
            src1.close()
            src2.close()
            out.close()
     
    def inittest(nb, tests):
        print('Grand ménage...')
        print('Création des répertoires cibles')
        for name in tests:
            if os.path.isdir(name):
                shutil.rmtree(name)
            os.mkdir(name)
        print('Suppression des fichiers')
        for item in os.listdir(os.getcwd()):
            if item.startswith('src'):
                os.remove(item)
        print('Création de 2 x ' + str(nb) + ' fichiers')
        letters = 'acgt'
        for index in range(0, nb):
            src1 = ''
            src2 = ''
            for i in range(1, 88):
                src1 += letters[randint(0, 3)]
                src2 += letters[randint(0, 3)]
            with open('src1_' + str(index), 'w') as f1:
                f1.write(src1 + '\n')
            with open('src2_' + str(index), 'w') as f2:
                f2.write(src2 + '\n')
     
    if __name__ == "__main__":
        nb = 10000
        tests = ['testopen', 'testmp', 'testmpmulti']
        inittest(nb, tests)
        print('Début des tests')
        print('testopen:')
        t1 = time.clock()
        repcible = os.path.join(os.getcwd(), 'testopen') + os.sep
        testopen(nb, 'src1', 'src2', repcible)
        t2 = time.clock()
        print(t2-t1)
        print(len(os.listdir(repcible)))
        print('testmp:')
        t1 = time.clock()
        lworkers = []
        workers = 4
        repcible = os.path.join(os.getcwd(), 'testmp') + os.sep
        manager = Manager()
        lproxy = manager.list()
        for i in range(nb):
            lproxy.append(str(i))
        for w in range(workers):
            lworkers.append(Process(target=testmp, args=(lproxy, nb, 'src1', 'src2',
                            repcible)))
        for w in lworkers:
            w.start()
        while len(lproxy) > 0:
            pass
        t2 = time.clock()
        print(t2-t1)
        time.sleep(2)
        print(len(os.listdir(repcible)))
        print('testmpmulti:')
        repcible = os.path.join(os.getcwd(), 'testmpmulti') + os.sep
        manager = Manager()
        endtime = manager.list()
        lproxy = manager.list()
        tclock = time.clock
        for i in range(nb):
            lproxy.append(str(i))
        p1 = Process(target=testmpmulti, args=(lproxy, endtime, tclock, nb, 'src1',
                     'src2', repcible))
        p2 = Process(target=testmpmulti, args=(lproxy, endtime, tclock, nb, 'src1',
                     'src2', repcible))
        p3 = Process(target=testmpmulti, args=(lproxy, endtime, tclock, nb, 'src1',
                     'src2', repcible))
        p4 = Process(target=testmpmulti, args=(lproxy, endtime, tclock, nb, 'src1',
                     'src2', repcible))
        p1.start()
        p2.start()
        p3.start()
        p4.start()
        while any((p1.is_alive(), p2.is_alive(), p3.is_alive(), p4.is_alive())):
            pass
        print(max(endtime)) # A revoir
        print(len(os.listdir(repcible)))
    Edit : N'oubliez pas de relancer les tests
    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
    Grand ménage...
    Création des répertoires cibles
    Suppression des fichiers
    Création de 2 x 100000 fichiers
    Début des tests
    testopen:
    60.48
    100000
    testmp:
    51.85
    100000
    testmpmulti:
    29.06
    100000
    .... 
    Grand ménage...
    Création des répertoires cibles
    Suppression des fichiers
    Création de 2 x 10000 fichiers
    Début des tests
    testopen:
    4.52
    10000
    testmp:
    3.28
    10000
    testmpmulti:
    2.75
    10000
    @++

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Verrouiller un grand nombre de fichiers
    Par justgreat dans le forum VB 6 et antérieur
    Réponses: 9
    Dernier message: 24/11/2009, 11h41
  2. Compiler un grand nombre de fichiers
    Par kaguouille dans le forum C
    Réponses: 1
    Dernier message: 13/02/2009, 18h17
  3. Lister un grand nombre de fichier ?
    Par noemi dans le forum VB.NET
    Réponses: 7
    Dernier message: 18/07/2007, 16h29
  4. grands nombre dans fichiers csv xls
    Par laurent.c123 dans le forum Documents
    Réponses: 3
    Dernier message: 09/07/2007, 22h28

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