GAE Python LXML - 超出软私有内存限制

时间:2013-02-22 12:19:38

标签: python google-app-engine memory lxml

我正在获取GZipped LXML文件并尝试将产品条目写入数据库模型。以前我遇到了本地内存问题,这些问题是通过SO(question)的帮助解决的。现在我把一切都工作并部署了,但是在服务器上我得到以下错误:

Exceeded soft private memory limit with 158.164 MB after servicing 0 requests total

现在我尝试了所有我知道的减少内存使用量,目前正在使用下面的代码。 GZipped文件大约7 MB,而解压缩它是80 MB。本地代码工作正常。我尝试将其作为HTTP请求以及Cron Job运行,但它没有任何区别。现在我想知道是否有任何方法可以提高效率。

关于SO的一些类似问题涉及Frontend和Backend规范,我不熟悉。我正在运行GAE的免费版本,这项任务必须每周运行一次。关于最佳前进方向的任何建议都将非常感激。

from google.appengine.api.urlfetch import fetch
import gzip, base64, StringIO, datetime, webapp2
from lxml import etree
from google.appengine.ext import db

class GetProductCatalog(webapp2.RequestHandler):
  def get(self):
    user = XXX
    password = YYY
    url = 'URL'

    # fetch gziped file
    catalogResponse = fetch(url, headers={
        "Authorization": "Basic %s" % base64.b64encode(user + ':' + password)
    }, deadline=10000000)

    # the response content is in catalogResponse.content
    # un gzip the file
    f = StringIO.StringIO(catalogResponse.content)
    c = gzip.GzipFile(fileobj=f)
    content = c.read()

    # create something readable by lxml
    xml = StringIO.StringIO(content)

    # delete unnecesary variables
    del f
    del c
    del content

    # parse the file
    tree = etree.iterparse(xml, tag='product')

    for event, element in tree:
        if element.findtext('manufacturer') == 'New York':
            if Product.get_by_key_name(element.findtext('sku')):
                    coupon = Product.get_by_key_name(element.findtext('sku'))
                    if coupon.last_update_prov != datetime.datetime.strptime(element.findtext('lastupdated'), "%d/%m/%Y"):
                        coupon.restaurant_name = element.findtext('name')
                        coupon.restaurant_id = ''
                        coupon.address_street = element.findtext('keywords').split(',')[0]
                        coupon.address_city = element.findtext('manufacturer')
                        coupon.address_state = element.findtext('publisher')
                        coupon.address_zip = element.findtext('manufacturerid')
                        coupon.value = '$' + element.findtext('price') + ' for $' + element.findtext('retailprice')
                        coupon.restrictions = element.findtext('warranty')
                        coupon.url = element.findtext('buyurl')
                        if element.findtext('instock') == 'YES':
                            coupon.active = True
                        else:
                            coupon.active = False
                        coupon.last_update_prov = datetime.datetime.strptime(element.findtext('lastupdated'), "%d/%m/%Y")
                        coupon.put()
                    else:
                        pass
            else:
                    coupon = Product(key_name = element.findtext('sku'))
                    coupon.restaurant_name = element.findtext('name')
                    coupon.restaurant_id = ''
                    coupon.address_street = element.findtext('keywords').split(',')[0]
                    coupon.address_city = element.findtext('manufacturer')
                    coupon.address_state = element.findtext('publisher')
                    coupon.address_zip = element.findtext('manufacturerid')
                    coupon.value = '$' + element.findtext('price') + ' for $' + element.findtext('retailprice')
                    coupon.restrictions = element.findtext('warranty')
                    coupon.url = element.findtext('buyurl')
                    if element.findtext('instock') == 'YES':
                        coupon.active = True
                    else:
                        coupon.active = False

                    coupon.last_update_prov = datetime.datetime.strptime(element.findtext('lastupdated'), "%d/%m/%Y")
                    coupon.put()
        else:
            pass

        element.clear()

UDPATE

根据Paul的建议,我实施了后端。经过一些麻烦后,它就像一个魅力 - 找到我在下面使用的代码。

我的backends.yaml看起来如下:

backends:
- name: mybackend
  instances: 10
  start: mybackend.app
  options: dynamic

我的app.yaml如下:

handlers:
- url: /update/mybackend
  script: mybackend.app
  login: admin

2 个答案:

答案 0 :(得分:2)

后端就像前端实例,但它们不能扩展,您必须在需要时停止并启动它们(或将它们设置为动态,这可能是您最好的选择)。

您可以在后端拥有高达1024MB的内存,因此它可能适用于您的任务。

https://developers.google.com/appengine/docs/python/backends/overview

  

App Engine后端是您的应用程序的实例,它们可以免于请求截止日期,并且可以访问比正常实例更多的内存(最大1GB)和CPU(最高4.8GHz)。它们专为需要更快性能,大量可寻址内存以及连续或长时间运行的后台进程的应用程序而设计。后端有多种尺寸和配置,并且需要正常运行而不是CPU使用。

     

后端可以配置为常驻或动态。居民   后端连续运行,让你依赖于他们的状态   内存随时间推移并执行复杂的初始化动态后端   当他们收到请求时就会存在,并被拒绝   闲置时;它们非常适合间歇性或受其驱动的工作   用户活动。有关两者之间差异的更多信息   驻留和动态后端,请参阅后端类型以及   讨论启动和关机。

听起来就像你需要的一样。免费使用级别也适用于您的任务。

答案 1 :(得分:0)

关于后端:查看您提供的示例 - 看起来您的请求只是由前端实例处理。

要让它由后端处理,请尝试调用以下任务:http://mybackend.my_app_app_id.appspot.com/update/mybackend

另外,我认为您可以从start: mybackend.app

中删除backends.yaml