2017-10-12 4 views
0

Mon projet consiste en un grand nombre d'importations placées dans un périmètre «global».Google App Engine: importation de modules dans le périmètre du gestionnaire par rapport à la portée globale

from google.appengine.ext import ndb 
from handlers import SomeHandler 
import logging 
import datetime # will only use this module ONCE 

Je veux utiliser le module datetime juste une fois dans un gestionnaire spécifique. Dois-je importer datetime dans le gestionnaire ou dois-je le laisser dans la portée globale? Il semble que l'importation locale montre des relations de dépendance plus claires. Y a-t-il un problème de performance ou d'autres inconvénients à prendre en compte?

Répondre

1

vous devriez importer par défi les modules au début de votre fichier qui le liera à la portée de ce fichier. Je pense que ce que vous faites s'appelle «chargement paresseux» des modules et cela peut causer des bogues à l'exécution, si le module n'est pas installé ou importé correctement. A propos, le fonctionnement de python est que chaque fois que vous importez un module, l'interpréteur regarde si le module a déjà été importé. Si elle a été importée, elle y fera référence. En un mot, il n'en crée pas une nouvelle instance.

Ce que je recommande est de créer un fichier pour votre classe de gestionnaire et d'importer datetime et tout ce que vous voulez au début de ce fichier.

1

Il n'y a aucun problème à importer à l'intérieur du gestionnaire (ou même à l'intérieur de la fonction get() si vous préférez) - Je l'utilise massivement.

Avantages de chargement paresseux:

  • application réduite temps de chargement
  • l'empreinte mémoire moyenne de votre application peut être beaucoup plus faible que l'empreinte mémoire totale nécessaire si vous charger tous les modules à temps init, même ceux qui rarement utilisé - moindre coût

Inconvénients de chargement paresseux:

  • non déterministe du temps de chargement de l'application
  • potentiel difficile à reproduire les bogues touchés au chargement du module retardé étant donné que les conditions exactes ne sont pas connues

connexes (dans le sens de chargement paresseux uniquement): App Engine: Few big scripts or many small ones?

1

Cacher les importations comme ceci est une optimisation; Lorsque vous envisagez d'optimiser, vérifiez que l'optimisation proposée sera réellement efficace.

Considérons d'abord l'exemple spécifique de datetime. Voici une application simple:

import sys 

import webapp2 


class Handler(webapp2.RequestHandler): 

    def get(self): 
     if 'datetime' in sys.modules: 
      self.response.write('The datetime module is already loaded.\n') 
     else: 
      self.response.write('The datetime module is not already loaded\n.') 
     self.response.write('%d modules have been loaded\n' % len(sys.modules)) 
     count = sum(1 for x in sys.modules.values() if '/lib64' in repr(x)) 
     self.response.write('%d standard library modules have been loaded\n' % count) 
     gcount = sum(1 for x in sys.modules.values() if 'appengine' in repr(x)) 
     self.response.write('%d appengine modules have been loaded\n' % gcount) 

application = webapp2.WSGIApplication([('/', Handler)]) 

Si nous visitons l'URL '/' on voit cette sortie:

Le module datetime est déjà chargé.

706 modules ont été chargés

95 modules de la bibliothèque standard ont été chargés

207 modules AppEngine ont été chargés

Même dans cette application minimale, datetime a déjà été importé par le SDK *. Une fois que Python a importé un module, les importations ultérieures ne coûtent qu'une seule recherche de dictionnaire, il n'y a donc aucun avantage à masquer l'importation. Etant donné que le SDK a déjà importé 95 modules de bibliothèque standard et 207 modules de SDK, il est peu probable que les importations de modules de bibliothèque ou de SDK standard couramment utilisés ne soient pas très utiles.

Cela laisse la question des importations de code d'application. Handlers peuvent être chargés paresseux en les déclarant comme des chaînes de routes, de sorte qu'ils ne sont pas importés jusqu'à ce que la route soit visité

app = webapp2.Application([('/foo', 'handlers.FooHandler')]) 

Cette technique permet d'optimiser le temps de démarrage sans les importations se cachent dans des classes ou des méthodes, si vous trouvez que c'est nécessaire.

Le coût de chargement paresseux, comme le soulignent les autres réponses, peut être des erreurs d'exécution inattendues. De plus, si vous choisissez de masquer les importations, cela peut également diminuer la lisibilité du code, provoquer des problèmes structurels, par exemple masquer les dépendances circulaires et donner un mauvais exemple aux développeurs moins expérimentés qui peuvent supposer que masquer les imports est idiomatique plutôt qu'une optimisation.

Ainsi, lorsque l'on considère l'optimisation de cette façon:

  • vérifier que l'optimisation est nécessaire: toutes les applications nécessitent des performances maximales absolue
  • Vérifiez que le problème droit est adressée; appels RPC sur App Engine ont tendance à dominer le profil des temps de réponse
  • pour vérifier que l'optimisation est efficace
  • considèrent les coûts dans le code maintenabilité

* Invoquant les sys.modules de SDK étant similaire à celle de la Le cloud computing est, je l'espère, une hypothèse raisonnable.