2017-10-12 57 views
0

我的项目由大量位于'全局'范围内的导入组成。Google App Engine:在处理程序范围内导入模块与全局范围

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

我想用datetime模块只是一次特定的处理器中。我应该在处理程序中导入日期时间还是应该将其保留在全局范围内?

import datetime # Should we import here? 

class BookHandler(webapp2.RequestHandler): 
    import datetime # Or, should we import here? 
    def get(self): 
     today = datetime.datetime.now() 

看起来像导入本地显示更清晰的依赖关系。是否有任何性能问题或其他缺点需要考虑?

回答

1

你应该在你的文件的开始处挑剔地导入模块,它将它绑定到该文件的范围。我认为你正在做的事情叫做“延迟加载”模块,如果模块没有正确安装或导入,它会在运行时导致错误。

顺便说一下,python的工作方式是,每当你导入一个模块时,解释器看起来是否已经导入了模块。如果它已经被导入,那么它会设置一个对它的引用。换句话说,它不会创建一个新的实例。

我推荐的是为你的处理程序类创建一个文件,并在该文件的开始处导入日期时间以及任何你想要的东西。

1

在处理程序内部导入没有问题(如果您愿意,甚至可以在get()函数内部导入) - 我正在大量使用它。延迟加载的

优点:

  • 减少应用程序的加载时间
  • 您的应用程序的平均内存占用量可能比您应该加载在启动时,所有模块所需的总内存占用低得多,甚至那些很少使用的 - 成本更低的延迟加载的

缺点:

  • 非确定性的应用程序加载时间
  • 潜力难以重现bug在延迟加载模块创下自确切条件是未知

相关(在延迟加载感只):App Engine: Few big scripts or many small ones?

1

像这样隐藏进口是一种优化;每当考虑是否优化时,验证提议的优化是否真的有效。

我们首先考虑datetime的具体示例。这里有一个简单的应用程序:

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)]) 

如果我们参观“/”的网址,我们看到这样的输出:

datetime模块已经加载。

706模块已经载入

95标准库模块已经载入

207的AppEngine模块已经载入

即使在这个最小的应用程序,datetime已经由SDK进口*。一旦Python导入了一个模块,进一步的导入只花费一次字典查找,所以隐藏导入没有任何好处。由于SDK已经导入了95个标准库模块和207个SDK模块,因此隐藏导入常用标准库或SDK模块的可能性不大。

这留下了导入应用程序代码的问题。处理程序可以延迟加载通过声明他们作为路线字符串,这样直到路线参观他们没有进口:

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

这种技术允许优化启动时间不隐藏在类或方法的进口,你应该找这是必要的。

其他答案指出,延迟加载的代价可能是意外的运行时错误。此外,如果您选择隐藏导入,它也会降低代码可读性,可能导致结构性问题,例如掩盖循环依赖性,并为经验较少的开发人员设置一个不好的示例,他们可能会认为隐藏导入是惯用的而不是优化。

因此,考虑以这种方式优化时:

  • 验证优化是必要的:不是所有的应用程序都需要绝对最大性能
  • 验证正确的问题正在得到解决;在App Engine上的RPC调用往往主宰响应时间
  • 配置文件以验证优化是有效
  • 考虑代码的可维护性

*费用依托SDK的sys.modules是相似的我希望云运行时是一个合理的假设。