Maison  >  Article  >  développement back-end  >  Quelles sont les techniques pour améliorer l’efficacité d’exécution de Python ?

Quelles sont les techniques pour améliorer l’efficacité d’exécution de Python ?

王林
王林avant
2023-05-11 14:13:061361parcourir

Avant de commencer, vous pouvez d'abord développer un décorateur Python qui compte le temps d'exécution des fonctions, qui sera utilisé plus tard pour les statistiques de temps après avoir utilisé diverses techniques Python.

# 导入时间提取的time模块
from time import time

import dis


def compute_time(func_):
    '''
    计算函数的运行时间
    '''

    def func_time(*arg, **kw):
        t1 = time()
        result = func_(*arg, **kw)
        t2 = time()
        print(f"{func_.__name__: >10} : {t2 - t1:.6f} 秒")
        return result

    return func_time

Nous avons développé la fonction de calcul du temps computation_time ci-dessus. Nous pouvons développer une fonction hello_world pour tester si elle est utilisée normalement.

@compute_time
def hello_world():
    print("hello_world!")


hello_world()

# hello_world!
# hello_world : 0.000000 秒

Grâce au test de la fonction hello_world, il est prouvé que notre décorateur de temps calculate_time peut normalement calculer le temps d'exécution de la fonction.

Ensuite, nous commençons à présenter formellement les cinq façons suivantes pour améliorer la vitesse d'exécution de Python et fournir des résultats d'exécution dans le temps.

1. Utilisation raisonnable des bibliothèques standard ou non standard

Vous ne devez pas sous-estimer les bibliothèques standard ou non standard de Python pendant le processus de développement. Pour être honnête, les mêmes blocs de code métier que nous écrivons parfois ne sont pas aussi parfaits que les grands. les gars.

Par exemple, dans l'activité suivante, nous devons convertir les valeurs d'une liste python en chaînes. Tout d'abord, regardez comment le bloc de code suivant est écrit.

# 初始化一个list列表
list_ = ['a', 'b', 'c'] * 10000


@compute_time
def func_1(list_=None):
    '''
    列表元素转字符串函数
    '''
    str_ = ''
    for s in list_:
        str_ = str_ + s
    return str_


func_1(list_)


# func_1 : 0.001999 秒

Utiliser la méthode traditionnelle écrite par moi-même pour convertir les étapes via l'exécution de la fonction func_1 ci-dessus est plus compliquée et prend 0,001999 seconde.

@compute_time
def func_2(list_=None):
    '''
    列表元素转字符串
    '''
    return ''.join(list_)


func_2(list_)

# func_2 : 0.000000 秒

Par rapport au temps d'exécution de la fonction func_1, le temps d'exécution de func_2 est presque négligeable et la décimale à six chiffres ne voit aucun changement.

2. Réduire l'utilisation des boucles

En fait, nous avons découvert à partir du processus de développement normal que les méthodes de traitement de données sérialisables utilisant la dérivation de liste, l'itération, etc. sont plus pratiques et efficaces que les boucles for.

Ci-dessous, nous pouvons également utiliser un exemple pour illustrer le problème. Par exemple, nous devons sélectionner un nombre dans une liste qui est divisible par 2.

# 初始化循环次数n
n = 100000


@compute_time
def func_3(n=None):
    list_ = []
    for m in range(n):
        if m % 2 == 0:
            list_.append(m)
    return list_


@compute_time
def func_4(n=None):
    return [m for m in range(n) if m % 2 == 0]


func_3(n)

func_4(n)

# func_3 : 0.004986 秒
# func_4 : 0.003014 秒

Grâce à la comparaison de la fonction func_3 et de la fonction func_4, tout d'abord, la méthode de func_4 est beaucoup plus simple que celle de func_3.

Et en termes de temps, func_4 utilise la dérivation de liste pour s'exécuter 1/4 plus vite que la boucle for ordinaire.

3. Faites attention à l'exécution répétée du code

En ce qui concerne l'exécution répétée du code, nous pouvons tous en faire l'expérience dans nos méthodes de développement habituelles, c'est-à-dire qu'il peut être exécuté une fois en tant que bloc de code public.

Vous pouvez ajouter des blocs de code pouvant être utilisés publiquement dans la boucle, ce qui n'affectera que l'efficacité d'exécution des blocs de code.

Par exemple, nous devons utiliser le module re de python pour rechercher certains éléments dans une chaîne. Voici deux façons de comparer les résultats temporels.

# 导入正则表达式匹配模块
import re


@compute_time
def func_5(str_=None):
    for s in str_:
        result = re.search(r'a*[a-z]?c', s)


@compute_time
def func_6(str_=None):
    repx = re.compile(r'a*[a-z]?c')
    for s in str_:
        result = repx.search(s)


func_5('abcdefg1234oks' * 1000)

func_6('abcdefg1234oks' * 1000)

# func_5 : 0.006999 秒
# func_6 : 0.002000 秒

En comparant les méthodes d'implémentation commerciale de func_5 et func_6, nous avons placé l'objet correspondant régulier de compilation du module re directement dans la couche externe de la boucle for, et le temps d'exécution a été directement réduit de plus de 3 fois.

En effet, l'utilisation de la recherche pour faire correspondre des objets normaux directement dans la boucle créera en permanence des objets correspondants réguliers dans la boucle, ce qui augmente la charge de traitement de la boucle for et entraîne un ralentissement de la vitesse.

4. Réduire l'utilisation de variables globales

En expliquant ce point, nous devons comprendre que les variables globales existent toujours et ne disparaîtront pas pendant l'exécution du programme.

Trop de variables globales entraîneront une occupation excessive de mémoire pendant le fonctionnement. Il sera plus efficace d'utiliser des variables locales par rapport aux variables globales.

Ci-dessous, nous utilisons des exemples de deux méthodes pour comparer le temps d'exécution des variables globales et des variables locales.

mes_1 = 'ss1'

mes_2 = 'ss2'

mes_3 = 'ss3'


@compute_time
def func_7():
    result = mes_1 + mes_2 + mes_3
    return result


@compute_time
def func_8():
    me_1 = 'ss1'
    me_2 = 'ss2'
    me_3 = 'ss3'
    result = me_1 + me_2 + me_3
    return result


func_7()

func_8()


# func_7 : 0.000997 秒
# func_8 : 0.000000 秒

Nous avons effectué un calcul d'addition ordinaire ci-dessus pour illustrer le problème. La façon dont la fonction func_8 utilise les variables locales est en effet plus rapide.

5. Utilisez des structures de données raisonnables

Dans la plupart des processus de développement Python, de nombreuses personnes doivent utiliser des listes pour traiter les données pour plus de commodité.

Python dispose de quatre structures de données intégrées : des listes, des tuples, des ensembles et des dictionnaires. L'utilisation de structures de données appropriées pour traiter les données dans des scénarios métier appropriés peut également améliorer l'efficacité de l'exécution des calculs.

Par exemple : ci-dessous, nous extrairons la valeur à la position d'index correspondante à partir d'une liste de listes et d'un tuple.

@compute_time
def func_9():
    data = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
    print(data[3])


@compute_time
def func_10():
    data = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h')
    print(data[3])

func_9()

func_10()

# func_9 : 0.000000 秒
# func_10 : 0.000000 秒

En exécutant les fonctions func_9 et func_10, nous avons constaté que la différence de temps entre les deux n'est pas grande, du moins le résultat ne peut pas être distingué à six décimales près.

print('func_9汇编产生的机器码:')
dis.dis(func_9)

print('func_10汇编产生的机器码:')
dis.dis(func_10)

Enfin, nous avons examiné les codes machine d'assemblage de func_9 et func_10 respectivement, et avons constaté que le traitement de liste génère évidemment plus de codes machine.

# func_9汇编产生的机器码:
#  30           0 LOAD_GLOBAL              0 (time)
#               2 CALL_FUNCTION            0
#               4 STORE_FAST               2 (t1)
#
#  31           6 LOAD_DEREF               0 (func_)
#               8 LOAD_FAST                0 (arg)
#              10 LOAD_FAST                1 (kw)
#              12 CALL_FUNCTION_EX         1
#              14 STORE_FAST               3 (result)
#
#  32          16 LOAD_GLOBAL              0 (time)
#              18 CALL_FUNCTION            0
#              20 STORE_FAST               4 (t2)
#
#  33          22 LOAD_GLOBAL              1 (print)
#              24 LOAD_DEREF               0 (func_)
#              26 LOAD_ATTR                2 (__name__)
#              28 LOAD_CONST               1 (' >10')
#              30 FORMAT_VALUE             4 (with format)
#              32 LOAD_CONST               2 (' : ')
#              34 LOAD_FAST                4 (t2)
#              36 LOAD_FAST                2 (t1)
#              38 BINARY_SUBTRACT
#              40 LOAD_CONST               3 ('.6f')
#              42 FORMAT_VALUE             4 (with format)
#              44 LOAD_CONST               4 (' 秒')
#              46 BUILD_STRING             4
#              48 CALL_FUNCTION            1
#              50 POP_TOP
#
#  34          52 LOAD_FAST                3 (result)
#              54 RETURN_VALUE
# func_10汇编产生的机器码:
#  30           0 LOAD_GLOBAL              0 (time)
#               2 CALL_FUNCTION            0
#               4 STORE_FAST               2 (t1)
#
#  31           6 LOAD_DEREF               0 (func_)
#               8 LOAD_FAST                0 (arg)
#              10 LOAD_FAST                1 (kw)
#              12 CALL_FUNCTION_EX         1
#              14 STORE_FAST               3 (result)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer