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 :

Optimisation bacth avec multiprocessing ?


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé Avatar de Tchicken
    Homme Profil pro
    Responsable d'exploitation informatique
    Inscrit en
    Août 2017
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Responsable d'exploitation informatique

    Informations forums :
    Inscription : Août 2017
    Messages : 108
    Par défaut Optimisation bacth avec multiprocessing ?
    Bonjour à tous,

    J’ai scripté en python une analyse financière et je cherche à optimiser les temps de traitement.
    Après quelques recherches, je suis tombé sur la librairie "multiprocessing" qui semble être la mieux adaptée à ce que je recherche.
    Je ne sais pas trop comment m'y prendre pour implémenter tout ça et je ne suis pas sûr que ce soit le bon choix...

    Dans ce programme, je charge un cube XBasesX (list à 3 dimensions) à partir d'une base de données.

    # Dimension 1 : les courses de l'hippodrome (560 courses du meeting d'hiver 2017 à Vincennes en attelé)
    # Dimension 2 : les chevaux de la course (de 9 à 20 partants, par défaut, j'ai fixé cette dimension à 20, c'est peut-être une erreur pour l'optimisation)
    # Dimension 3 : les rubriques des chevaux et les zones de travail (14 rubriques de classements qualificatifs indices 4 à 17, les indices 0 à 3 et 18 servent aux calculs et 19 au stockage des rapports)

    Voici la fonction que j'appelle en lui donnant en paramètres les coefficients multiplicateurs à appliquer à chacune des rubriques, cette fonction appelle aussi en fin de traitement une autre fonction qui enregistre le résultat de l'analyse si le bilan financier s'est amélioré.

    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
    # Fonction de traitement d'un cycle complet sur le cube
    def CycleToutesCourses(CoefRub):
        global XBasesX
        global NbCycles
        global LieuCourse
        global Discipline
        global SvNbCoursesGains
        global SvMontantGains
        # Initialisation des zones de calcul pour le bilan financier
        NbCoursesGains = 0
        MontantGains = 0
        MontantJeux = 0
        CptEcartMoyen = 0
        CptEcartMaxi = 0
        Z4Calcules = 0
        EcartMoyen = 0
        EcartMaxi = 0
        Ecart = 0
        # on boucle sur les courses charges dans XBasesX
        for BasesX in XBasesX:
            # Calcul des points cumulés pour chaque cheval de la course lignes 0 à 19
            for Bases in BasesX:
                # Cumul des 14 rubriques colonnes 3 à 17
                for Rub in range(0,14):
                    Bases[3] = Bases[3] + (CoefRub[Rub] * Bases[Rub + 4])
            # Tri préalable sur colonne 8 classement ClaStatsCombi
            BasesX = sorted(BasesX, key=itemgetter(8))
            # Tri sur colonne 3 Cumul des valeurs dégressives de 5 à 1 points pour les 5 premiers des classements de chaque rubriques
            BasesX = sorted(BasesX, key=itemgetter(3), reverse=True)
            # Bilan Z4 combiné 8 chevaux 70€
            MontantJeux += 70
            Z4 = 0
            for i in range(0,9):
                if BasesX[i][2] == 1 or BasesX[i][2] == 2 or BasesX[i][2] == 3 or BasesX[i][2] == 4:
                    Z4 += 1
            if Z4 == 4:
                NbCoursesGains += 1
                if BasesX[0][19] > 0:
                    MontantGains = MontantGains + BasesX[0][19]
                else:
                    # Gains approximatifs calculés lorsque le rapport du Z4 est inconnu 
                    if (BasesX[1][19] * BasesX[2][19] * BasesX[3][19] / 10) > 0:
                        MontantGains = MontantGains + (BasesX[1][19] * BasesX[2][19] * BasesX[3][19] / 10)
                    else:
                        # 80 € par défaut si incalculable
                        MontantGains = MontantGains + 80
                    Z4Calcules += 1
                if CptEcartMaxi > EcartMaxi:
                    EcartMaxi = CptEcartMaxi
                EcartMoyen = EcartMoyen + CptEcartMoyen
                if CptEcartMoyen != 0:
                    Ecart += 1
                CptEcartMoyen = 0
                CptEcartMaxi = 0
            else:
                CptEcartMoyen += 1
                CptEcartMaxi += 1
            # on sort du cycle sous les conditions suivantes =>
    	    # Au bout 10 courses analysées, si moins de 2 courses ont été pronostiquées
    	    # Au bout 20 courses analysées, si moins de 5 courses ont été pronostiquées 
    	    # Au bout 50 courses analysées, si moins de 11 courses ont été pronostiquées 
    	    # Au bout 100 courses analysées, si moins de 21 courses ont été pronostiquées 
            # Si l'écart maximum est supérieur à 10
            if (MontantJeux > 630 and NbCoursesGains < 2) or (MontantJeux > 1330 and NbCoursesGains < 5) or (MontantJeux > 3430 and NbCoursesGains < 11) or (MontantJeux > 6930 and NbCoursesGains < 21) or EcartMaxi > 10:
                break
        # Enregistrement du bilan financier dans Parametres
        # Si le montant des gains ou le nombre de courses gagnées s'est amélioré
        if NbCoursesGains > SvNbCoursesGains or MontantGains > SvMontantGains:
            if EcartMoyen > 0:
                EcartMoyen = round(EcartMoyen / Ecart, 2)
            EnregistreParam(CoefRub,EcartMoyen,EcartMaxi,NbCourses,NbCoursesGains,MontantJeux,MontantGains,Z4Calcules)
            print(NbCycles," - ",strftime("%Y%m%d %H:%M",gmtime())," - ",CoefRub," - NbCG=",NbCoursesGains," - Gains=",MontantGains," - Z4C=",Z4Calcules)
            if NbCoursesGains > SvNbCoursesGains:
                SvNbCoursesGains = NbCoursesGains
            if MontantGains > SvMontantGains:
                SvMontantGains = MontantGains
        else:
            if NbCycles % 50000 == 0:
                print(NbCycles," - ",strftime("%Y%m%d %H:%M",gmtime())," - ",CoefRub," - NbCG=",NbCoursesGains," - Gains=",MontantGains," - Z4C=",Z4Calcules)
    Et j'appelle cette fonction à partir de cette boucle où je fais varier les coefficients multiplicateurs en boucles imbriquées :

    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
    # Boucles de calcul de l'analyse financière
    SvNbCoursesGains = 0
    SvMontantGains = 0
    NbCycles = 0
    # Rubrique CX ***
    for ClaCX in range(0,3):
        # Rubrique CRI ***
        for ClaCRIFX in range(0,3):
            # Rubrique FOR ***
            for IndForme in range(0,3):
                # Rubrique GEN ***
                for ClaTMatic in range(0,3):
                    # Rubrique STR ***
                    for ClaStatsCombi in range(0,3):
                        # Rubrique DRI ***
                        for ClasRD in range(0,3):
                            # Rubrique ENT ***
                            for ClasRE in range(0,3):
                                # Rubrique CM ***
                                for ClaCote in range(0,3):
                                    # Rubrique REU ***
                                    for ClasCoefReussite in range(0,3):
                                        # Rubrique AR ***
                                        for ClaAR in range(0,3):
                                            # Rubrique OR ***
                                            for ClaOR in range(0,3):
                                                # Rubrique RUB ***
                                                for ClaRub in range(0,3):
                                                    # Rubrique HIS ***
                                                    for ClaHisto in range(0,3):
                                                        # Rubrique ST ***
                                                        for ClasStats in range(0,3):
                                                            # Liste des coefficients des 14 rubriques
                                                            CoefRub = [ClaCX,ClaCRIFX,IndForme,ClaTMatic,ClaStatsCombi,ClasRD,ClasRE,ClaCote,ClasCoefReussite,ClaAR,ClaOR,ClaRub,ClaHisto,ClasStats]
                                                            NbCycles += 1
                                                            CycleToutesCourses(CoefRub)
    Déjà, si vous avez des suggestions pour optimiser au maximum ce code, je suis preneur.

    D'autre part, l'un d'entre vous pourrait-il m'aider à implémenter le "multiprocessing" sur ce code s.v.p.

    Jusqu'à maintenant j'ai pu faire varier mes coefficients multiplicateurs de 0 à 2, ce traitement dans cette configuration a duré moins de 10 heures.
    Mais je souhaiterais les faire varier de 0 à 5 et là, selon mes calculs, j'en ai pour plusieurs dizaines d'années !

    Merci de votre aide. Tchicken.

  2. #2
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Salut

    Avant de penser multiprocess il y a déjà plein d'optimisation à faire dans votre code. Votre ordinateur fait des opérations. Dites vous bien que si vous lui en épargner, vous gagnez du temps d'éxcution.

    Donc le premier travail c'est de mettre un chrono sur votre fonction CycleToutesCourses
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    from time import time
     
    t0=time()
    ### execution de votre fonction
    print("temps d'execution (en secondes): ",time()-t0)
    et une fois que vous avez cet indicateur réduiser le nombre d'opérations de votre fonction et constater l'impact sur le temps d'éxécution.

    Même si vous ne gagner que quelque micro secondes, c'est déjà énorme. Car Dites vous bien qu'après avec vos 14 boucles for imbriquées, avec 3 valeurs différentes pour chaque vous faites 3 puissance 14 fois appel à cette fonction, soit environ 5 million de fois !

    Je vous donne quelques exemples :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if BasesX[i][2] == 1 or BasesX[i][2] == 2 or BasesX[i][2] == 3 or BasesX[i][2] == 4:
    s'écrit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if BasesX[i][2] in (1,2,3,4):
    ce qui vous évite l'extraction de la donnée 4 fois.
    voire même si vous savez que BasesX[i][2] est nécéssairement un entier, vous pouvez réduire le nombre de test ainsi :
    et vous passer de 4 extractions + 4 tests + 3 connecteurs logique à 1 extraction + 2 tests + 1 connecteur logique (de 11 opérations, on passe à 4)

    Autre exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
                    if (BasesX[1][19] * BasesX[2][19] * BasesX[3][19] / 10) > 0:
                        MontantGains = MontantGains + (BasesX[1][19] * BasesX[2][19] * BasesX[3][19] / 10)
    Pourquoi faire calculer à votre ordinateur 2 fois cette grosse expression ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
                  a = BasesX[1][19] * BasesX[2][19] * BasesX[3][19] / 10
                  if a > 0:
                        MontantGains += a
    Et je ne parle pas là des variables qui sont en global, dont on ne sait absolument pas d'où elles viennent, et qui probablement pourraient être construites de manière plus judicieuse certainement (des array numpy peut etre), ainsi que des doubles tris qui ont l'air très suspects ...

  3. #3
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    J'en profite aussi pour vous donner la syntaxe réduite de vos 14 boucles for immonde imbriquées, qui montre déjà l'utilité de numpy :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    import numpy as np
     
    for CoefRub in np.ndindex( (3,)*14 ):
           NbCycles += 1
           CycleToutesCourses(CoefRub)

  4. #4
    Membre confirmé Avatar de Tchicken
    Homme Profil pro
    Responsable d'exploitation informatique
    Inscrit en
    Août 2017
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Responsable d'exploitation informatique

    Informations forums :
    Inscription : Août 2017
    Messages : 108
    Par défaut
    Tout d'abord un grand merci pour ces précieux conseils.
    Et je vous demande pardon pour mon code exécrable (Après 30 ans de VB, je suis passé au python le mois dernier)
    Du coup j'ai fait une revue de mon code et je le remet en ligne ci-dessous en intégralité.
    Détail de la création du Cube avec la boucle sur la base de données qui appelle les fonctions AMHippo et SHHippo pour l'alimenter.
    Les variables global me simplifient le partage de données avec les différentes fonctions

    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
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    # -*- coding: utf-8 -*
    # BasesX(i, 0)   numéro
    # BasesX(i, 1)   nombre de citations dans les 5 premiers de chaque classement rubriques
    # BasesX(i, 2)   place à* l'arrivée
    # BasesX(i, 3)   cumul des valeurs dégressives de 5 à 1 points pour les 5 premiers des classements rubriques
    # BasesX(i, 4)   classement ClaCX
    # BasesX(i, 5)   classement ClaCRIFX
    # BasesX(i, 6)   classement IndForme
    # BasesX(i, 7)   classement ClaTMatic
    # BasesX(i, 8)   classement ClaStatsCombi
    # BasesX(i, 9)   classement ClasRD
    # BasesX(i, 10)  classement ClasRE
    # BasesX(i, 11)  classement ClaCote
    # BasesX(i, 12)  classement ClasCoefReussite
    # BasesX(i, 13)  classement ClaAR
    # BasesX(i, 14)  classement ClaOR
    # BasesX(i, 15)  classement ClaRub
    # BasesX(i, 16)  classement ClaHisto
    # BasesX(i, 17)  classement ClasStats
    # BasesX(i, 18)  classement BasesX(i, 3) cumul des valeurs dégressives de 5 à*1 points pour les 5 premiers des classements rubriques
    # BasesX(i, 19)  QuarteD, CouplePlace12, CouplePlace13, CouplePlace23 colonnes 0 à 3
    import sqlite3
    import numpy
    from time import gmtime, strftime
    from operator import itemgetter
    from time import time
    # connexion BDD
    conn = sqlite3.connect("Vincennes.sqlite")
    conn.row_factory = sqlite3.Row
    # Initialisation du tableau de X courses XBasesX constitué de tableaux de courses BasesX
    XBasesX = []
    # Tableau des noms des 14 ou 16 rubriques étudiées
    #LibRub = ["ClaCX","ClaIDC","ClaCRIFX","IndForme","ClaTMatic","ClaStatsCombi","ClasRD","ClasRE","ClaCote","ClaCFP","ClasCoefReussite","ClaAR","ClaOR","ClaRub","ClaHisto","ClasStats"]
    LibRub = ["ClaCX","ClaCRIFX","IndForme","ClaTMatic","ClaStatsCombi","ClasRD","ClasRE","ClaCote","ClasCoefReussite","ClaAR","ClaOR","ClaRub","ClaHisto","ClasStats"]
    SvNbCoursesGains = 0
    SvMontantGains = 0
    # Rubriques classiques
    def AMHippo(NumGeny,NumCourse,Partants,Distance,LibRub,Rub):
        global BasesX
        global conn
        global LieuCourse
        global Discipline
        # TabChevaux = [[0 for i in range(2)] for j in range(20)]
        TabChevaux = [[0] * 2 for _ in range(20)]
        cur = conn.cursor()
        cur.execute("SELECT Numero, PlaceArrivee FROM Chevaux WHERE NumGeny='" + NumGeny + "' and NumCourse=" + str(NumCourse) + " ORDER BY " + LibRub)
        for row in cur.fetchall():
            TabChevaux[i][0] = row["Numero"]
            TabChevaux[i][1] = row["PlaceArrivee"]
        if Discipline == "ATTELE" or Discipline == "MONTE":
            if Distance < 2701:
                if Distance < 2401:
                    DistanceMin = "1500"
                    DistanceMax = "2400"
                else:
                    DistanceMin = "2401"
                    DistanceMax = "2700"
            else:
                DistanceMin = "2701"
                DistanceMax = "4500"
        elif Discipline == "PLAT":
            if Distance < 1801:
                if Distance < 1501:
                    DistanceMin = "500"
                    DistanceMax = "1500"
                else:
                    DistanceMin = "1501"
                    DistanceMax = "1800"
            else:
                DistanceMin = "1801"
                DistanceMax = "4500"
        else:
            if Distance < 7500:
                if Distance < 5001:
                    if Distance < 3501:
                        DistanceMin = "2500"
                        DistanceMax = "3500"
                    else:
                        DistanceMin = "3501"
                        DistanceMax = "5000"
                else:
                    DistanceMin = "5001"
                    DistanceMax = "7500"
        if Partants > 8 and Partants < 13:
            PartantsMin = "9"
            PartantsMax = "12"
        elif Partants > 12 and Partants < 17:
            PartantsMin = "13"
            PartantsMax = "16"
        else:
            PartantsMin = "17"
            PartantsMax = "20"
        cur = conn.cursor()
        cur.execute("SELECT Classement, PrctFreqT, PrctFreqZ FROM StatsRubHippo WHERE LieuCourse='" + LieuCourse + "' and Discipline='" + Discipline + "' and Rubrique='" + LibRub + "' and DistanceMin=" \
                    + DistanceMin + " and DistanceMax=" + DistanceMax + " and PartantsMin=" + PartantsMin + " and PartantsMax=" + PartantsMax + " ORDER BY PrctFreqZ desc, Classement")
        for row in cur.fetchall():
            if row["Classement"] <= Partants:
                for j in range(0,Partants):
                    if BasesX[j][0] == TabChevaux[row["Classement"]][0]:
                        BasesX[j][1] += 1
                        BasesX[j][2] = TabChevaux[row["Classement"]][1]
                        BasesX[j][Rub + 4] += (row["PrctFreqZ"])
     
    # Rubriques combinées
    def SHHippo(DateReunion,NumReunion,NumCourse):
        global BasesX
        global conn
        cur = conn.cursor()
        cur.execute("SELECT Numero, PlaceArrivee, FrequenceReussite FROM DatesChevaux WHERE DateReunion='" + DateReunion + "' and NumReunion=" + str(NumReunion) + " and NumCourse=" + str(NumCourse) + " ORDER BY ClaFrqReussite")
        for row in cur.fetchall():
            for j in range(0,20):
                if BasesX[j][0] == row["Numero"] :
                    BasesX[j][1] += 1
                    BasesX[j][2] = row["PlaceArrivee"]
                    BasesX[j][8] += (19 - (j * 2))
     
    # Enregistrement du résultat de l'analyse financière dans la base de données
    def EnregistreParam(CoefRub,EcartMoyen,EcartMaxi,NbCourses,NbCoursesGains,MontantJeux,MontantGains,Z4Calcules):
        global conn
        global LieuCourse
        global Discipline
        global DateDebPer
        global DateFinPer
        #LibCoef = ["CoefRubCX","CoefRubCRI","CoefRubIDC","CoefRubFOR","CoefRubTGE","CoefRubSTR","CoefRubDRI","CoefRubENT","CoefRubCM","CoefRubCFP","CoefRubREU","CoefRubAR","CoefRubOR","CoefRubRUB","CoefRubHIS","CoefRubST"]
        LibRub = ["RubCX","RubCRI","RubFOR","RubTGE","RubSTR","RubDRI","RubENT","RubCM","RubREU","RubAR","RubOR","RubRUB","RubHIS","RubST"]
        LibCoef = ["CoefRubCX","CoefRubCRI","CoefRubFOR","CoefRubTGE","CoefRubSTR","CoefRubDRI","CoefRubENT","CoefRubCM","CoefRubREU","CoefRubAR","CoefRubOR","CoefRubRUB","CoefRubHIS","CoefRubST"]
        # Chargement des bilans positifs en fonction des valeurs paramètrées
        cur = conn.cursor()
        cur.execute("SELECT LieuCourse, Discipline, Jeu, NbCoursesGains, MontantGains FROM Parametres WHERE Jeu='nb'")
        row = cur.fetchone()
        if NbCoursesGains > row["NbCoursesGains"]: 
            Bilan = "UPDATE Parametres set "
            for i in range(0,14):
                if CoefRub[i] == 0:
                    Bilan = Bilan + LibRub[i] + "=0, " + LibCoef[i] + "=" + str(CoefRub[i]) + ","
                else:
                    Bilan = Bilan + LibRub[i] + "=1, " + LibCoef[i] + "=" + str(CoefRub[i]) + ","
            Bilan = Bilan + " EcartMoyen=" + str(EcartMoyen) + ", EcartMaxi=" + str(EcartMaxi) + ", Difficulte=100, NbCourses=" + str(NbCourses) + ", NbCoursesGains=" + str(NbCoursesGains)
            Bilan = Bilan + ", MontantJeux="+ str(MontantJeux) + ", MontantGains=" + str(MontantGains) + ", Z4Calcules=" + str(Z4Calcules) + ", DateDebPer='" + DateDebPer + "', DateFinPer='" + DateFinPer + "'"
            Bilan = Bilan + " WHERE LieuCourse='" + LieuCourse + "' and Discipline='" + Discipline + "' and Jeu='nb'"
            cur.execute(Bilan)
            conn.commit()
        cur.execute("SELECT LieuCourse, Discipline, Jeu, NbCoursesGains, MontantGains FROM Parametres WHERE Jeu='mt'")
        row = cur.fetchone()
        if MontantGains > row["MontantGains"]: 
            Bilan = "UPDATE Parametres set "
            for i in range(0,14):
                if CoefRub[i] == 0:
                    Bilan = Bilan + LibRub[i] + "=0, " + LibCoef[i] + "=" + str(CoefRub[i]) + ","
                else:
                    Bilan = Bilan + LibRub[i] + "=1, " + LibCoef[i] + "=" + str(CoefRub[i]) + ","
            Bilan = Bilan + " EcartMoyen=" + str(EcartMoyen) + ", EcartMaxi=" + str(EcartMaxi) + ", Difficulte=100, NbCourses=" + str(NbCourses) + ", NbCoursesGains=" + str(NbCoursesGains)
            Bilan = Bilan + ", MontantJeux="+ str(MontantJeux) + ", MontantGains=" + str(MontantGains) + ", Z4Calcules=" + str(Z4Calcules) + ", DateDebPer='" + DateDebPer + "', DateFinPer='" + DateFinPer + "'"
            Bilan = Bilan + " WHERE LieuCourse='" + LieuCourse + "' and Discipline='" + Discipline + "' and Jeu='mt'"
            cur.execute(Bilan)
            conn.commit()
        cur.close
    # Fonction de traitement d'un cycle complet sur le cube
    def CycleToutesCourses(CoefRub):
        global XBasesX
        global NbCycles
        global LieuCourse
        global Discipline
        global SvNbCoursesGains
        global SvMontantGains
        # Initialisation des zones de calcul pour le bilan financier
        NbCoursesGains = 0
        MontantGains = 0
        MontantJeux = 0
        CptEcartMoyen = 0
        CptEcartMaxi = 0
        Z4Calcules = 0
        EcartMoyen = 0
        EcartMaxi = 0
        Ecart = 0
        t0=time()
        # on boucle sur les courses charges dans XBasesX
        for BasesX in XBasesX:
            # Calcul des points cumulés pour chaque cheval de la course lignes 0 à 19
            for Bases in BasesX:
                # Cumul des 14 rubriques colonnes 3 à 17
                for Rub in range(0,14):
                    Bases[3] += (CoefRub[Rub] * Bases[Rub + 4])
            # Tri préalable sur colonne 8 classement ClaStatsCombi
            BasesX = sorted(BasesX, key=itemgetter(8))
            # Tri sur colonne 3 Cumul des valeurs dégressives de 5 à 1 points pour les 5 premiers des classements de chaque rubriques
            BasesX = sorted(BasesX, key=itemgetter(3), reverse=True)
            # Bilan Z4 combiné 8 chevaux 70€
            MontantJeux += 70
            Z4 = 0
            for i in range(0,9):
                if 0<BasesX[i][2]<5:
                    Z4 += 1
            if Z4 == 4:
                NbCoursesGains += 1
                GZ4 = BasesX[0][19]
                if GZ4 > 0:
                    MontantGains += GZ4
                else:
                    # Gains approximatifs calculés lorsque le rapport du Z4 est inconnu 
                    GA = BasesX[1][19] * BasesX[2][19] * BasesX[3][19]
                    if GA > 0:
                        MontantGains += GA / 10
                    else:
                        # 80 € par défaut si incalculable
                        MontantGains += 80
                    Z4Calcules += 1
                if CptEcartMaxi > EcartMaxi:
                    EcartMaxi = CptEcartMaxi
                EcartMoyen = EcartMoyen + CptEcartMoyen
                if CptEcartMoyen != 0:
                    Ecart += 1
                CptEcartMoyen = 0
                CptEcartMaxi = 0
            else:
                CptEcartMoyen += 1
                CptEcartMaxi += 1
    	# on sort du cycle sous les conditions suivantes =>
    	# Au bout 10 courses analysées, si moins de 2 courses ont été pronostiquées
    	# Au bout 20 courses analysées, si moins de 5 courses ont été pronostiquées 
    	# Au bout 50 courses analysées, si moins de 11 courses ont été pronostiquées 
    	# Au bout 100 courses analysées, si moins de 21 courses ont été pronostiquées 
    	# Si l'écart maximum est supérieur à 10
            if (MontantJeux > 630 and NbCoursesGains < 2) or (MontantJeux > 1330 and NbCoursesGains < 5) or (MontantJeux > 3430 and NbCoursesGains < 11) or (MontantJeux > 6930 and NbCoursesGains < 21) or EcartMaxi > 10:
                break
        # Enregistrement du bilan financier dans Parametres
        # Si le montant des gains ou le nombre de courses gagnées s'est amélioré
        if NbCoursesGains > SvNbCoursesGains or MontantGains > SvMontantGains:
            if EcartMoyen > 0:
                EcartMoyen = round(EcartMoyen / Ecart, 2)
            EnregistreParam(CoefRub,EcartMoyen,EcartMaxi,NbCourses,NbCoursesGains,MontantJeux,MontantGains,Z4Calcules)
            print(NbCycles," - ",strftime("%Y%m%d %H:%M",gmtime())," - ",CoefRub," - NbCG=",NbCoursesGains," - Gains=",MontantGains," - Z4C=",Z4Calcules)
            if NbCoursesGains > SvNbCoursesGains:
                SvNbCoursesGains = NbCoursesGains
            if MontantGains > SvMontantGains:
                SvMontantGains = MontantGains
        else:
            if NbCycles % 50000 == 0:
                print(NbCycles," - ",strftime("%Y%m%d %H:%M",gmtime())," - ",CoefRub," - NbCG=",NbCoursesGains," - Gains=",MontantGains," - Z4C=",Z4Calcules)
        #print("Temps d'execution : ",time()-t0," Sec.")
    #
    # Création du Cube :
    #
    #   Dimension 1 : les courses de l'hippodrome
    #   Dimension 2 : les chevaux de la course
    #   Dimension 3 : les rubriques des chevaux
    #
    # Chargement des données Reunions, Courses et rubriques pour 1 Hippodrome et 1 Discipline
    # Par exemple pour Vincennes en attelé 566 courses pendant le meeting du 1er octobre 2017 au 31 mars 2018 :
    # On divise l'année en 2, meeting (1er octobre au 31 mars) et hors meeting (1er avril au 30 septembre)
    # on charges les x courses dans le tableau XBasesX qui servira de base pour l'étude financières
    # Dans le cas de Vincennes, 
    curR = conn.cursor()
    curR.execute("SELECT NumGeny, LieuCourse, DateReunion, NumReunion FROM Reunions ORDER BY substr(DateReunion, 7, 4)||substr(DateReunion, 4,2)||substr(DateReunion, 1,2) desc")
    NbCourses = 0
    for rowR in curR.fetchall():
        if NbCourses == 0:
            DateDebPer = rowR["DateReunion"]
            LieuCourse = rowR["LieuCourse"]
        # Chargement des données courses
        curC = conn.cursor()
        curC.execute("SELECT NumGeny, NumCourse, Discipline, Partants, Distance, Premier, Deuxieme, Troisieme, Quatrieme, Cinquieme, round(CouplePlace12), round(CouplePlace23), \
        round(CouplePlace13), round(Trio), round(QuarteD) FROM Courses WHERE Partants>9 and NumGeny='" + rowR["NumGeny"] + "' and Discipline='ATTELE' ORDER BY NumCourse")
        for rowC in curC.fetchall():
            NbCourses = NbCourses + 1
            Discipline = rowC["Discipline"]
            # Initialisation du tableau 1 course BasesX de 19 colonnes et 20 lignes 
            BasesX = [[0] * 20 for _ in range(20)]
            # chargement du tableau 1 course avec les numéro des chevaux de 1 à* 20
            for i in range(0,20):
                BasesX[i][0] = i + 1
                # On initialise les classements rubriques à 99 pour les tris croissants
    	    #
                for j in range(4,18):
                    BasesX[i][j] = 99
            # Boucle d'appels à la fonction de chargement des valeurs des 16 rubriques statistiques dans BasesX
            for Rub in range(0,14):
                if Rub==4:
                    # Rubriques combinées
                    SHHippo(rowR["DateReunion"],rowR["NumReunion"],rowC["NumCourse"]) 
                else:
                    # Rubriques classiques
                    AMHippo(rowR["NumGeny"],rowC["NumCourse"],rowC["Partants"],rowC["Distance"],LibRub[Rub],Rub) 
            BasesX[0][19] = int(rowC["round(QuarteD)"])
            BasesX[1][19] = int(rowC["round(CouplePlace12)"])
            BasesX[2][19] = int(rowC["round(CouplePlace13)"])
            BasesX[3][19] = int(rowC["round(CouplePlace23)"])
            XBasesX.append(BasesX)
        curC.close()
        DateFinPer = rowR["DateReunion"]
    curR.close()
    # Boucles de calcul de l'analyse financière
    SvNbCoursesGains = 0
    SvMontantGains = 0
    NbCycles = 0
    print(NbCycles," - ",strftime("%Y%m%d %H:%M",gmtime()))
    # variation de 0 à 3 des coefficients des 14 rubriques
    for CoefRub in numpy.ndindex( (3,)*14 ):
        NbCycles += 1
        CycleToutesCourses(CoefRub)
    Dans cette configuration, j'obtiens les temps de traitement suivants :

    Temps d'execution :  0.002000093460083008  Sec.
    Temps d'execution :  0.002000093460083008  Sec.
    Temps d'execution :  0.002000093460083008  Sec.
    Temps d'execution :  0.0029997825622558594  Sec.
    Temps d'execution :  0.002000093460083008  Sec.
    Temps d'execution :  0.0019998550415039062  Sec.
    Temps d'execution :  0.003000020980834961  Sec.
    Temps d'execution :  0.002000093460083008  Sec.
    Temps d'execution :  0.0019998550415039062  Sec.
    Temps d'execution :  0.0030002593994140625  Sec.
    
    NbCycles - Date et heure       - Coéfficients multiplicateurs ...
    0            -  20181128 14:35
    19684     -  20181128 14:36  -  (0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0)  - NbCG= 7  - Gains= 1596  - Z4C= 1
    50000     -  20181128 14:39  -  (0, 0, 0, 0, 2, 1, 1, 2, 1, 2, 0, 2, 1, 1)  - NbCG= 7  - Gains= 1596  - Z4C= 1
    Soit 50000 cycles en 4 minutes environ, 750000 à l'heure, soit environ 6H30.
    Ce qui donne dans le cas des coefficients multiplicateurs de 0 à 2, théoriquement une baisse d'un 1/3 de la durée de traitement.

    Merci lg_53

  5. #5
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Autre optim :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
            BasesX = sorted(BasesX, key=itemgetter(8))
            BasesX = sorted(BasesX, key=itemgetter(3), reverse=True)
    1er optim : utiliser la fonction sort qui trie la liste "sur place" plutot que de se réserver une nouvelle place en mémoire et de réaffecter ensuite

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    BasesX.sort(key=itemgetter(8))
    BasesX.sort( key=itemgetter(3), reverse=True)
    2eme optim : plutot que de faire 2 tris, n'en faire qu'un seul avec une clé double (python sait comparer des tuples) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    BasesX.sort( key= lambda x : (-x[3],x[8])))
    L'astuce ici est de lettre un signe - pour imiter un tri dans l'ordre inverse sur cette clé.

    Vous pouvez mettre les time pile autour de cela pour mesurer les gains.


    Vous pouvez également poussez les investigations plus loin en mettant des time un peu partout pour savoir ce qui prend le plus de temps (et ce qu'il serait donc de bon gout d'optimiser). Le module cProfile peut aussi vous faire cela de manière très complète.

    Il nous faudrait un fichier, ou formuler les choses différemment pour qu'on puisse faire tourner qqch si vous voulez qu'on puisse vous aidez plus.

    Bonne soirée

  6. #6
    Membre confirmé Avatar de Tchicken
    Homme Profil pro
    Responsable d'exploitation informatique
    Inscrit en
    Août 2017
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Responsable d'exploitation informatique

    Informations forums :
    Inscription : Août 2017
    Messages : 108
    Par défaut
    Bonsoir lg_53,

    un grand merci pour ton aide, j'ai le fichier sqlite en pièce jointe. Je reprendrai le codage demain.
    Fichiers attachés Fichiers attachés

Discussions similaires

  1. optimisation requête avec jointures externes
    Par beurtom dans le forum Oracle
    Réponses: 14
    Dernier message: 16/10/2006, 16h50
  2. [Optimisation] Requetes avec agregats et vue
    Par rad_hass dans le forum Décisions SGBD
    Réponses: 1
    Dernier message: 14/01/2006, 13h39
  3. Optimisation requete avec sous-requetes multiples
    Par gege.boubou dans le forum Requêtes
    Réponses: 3
    Dernier message: 08/09/2005, 10h42
  4. optimisation requetes avec base de données
    Par flogreg dans le forum Décisions SGBD
    Réponses: 9
    Dernier message: 05/07/2005, 14h54
  5. Optimisation HTML avec Tomcat
    Par zekey dans le forum Tomcat et TomEE
    Réponses: 2
    Dernier message: 23/03/2005, 12h24

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