0

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

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

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

SO上的一些类似问题参考了我不熟悉的前端和后端规范。我正在运行 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

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

我的 backends.yaml 如下所示:

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

而我的 app.yaml 如下:

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

2 回答 2

2

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

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

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

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

后端可以配置为驻留或动态。常驻后端持续运行,允许您依赖其内存状态随时间推移执行复杂的初始化。动态后端在收到请求时出现,在空闲时关闭;它们非常适合间歇性工作或由用户活动驱动的工作。有关常驻后端和动态后端之间差异的更多信息,请参阅后端类型以及启动和关闭的讨论。

这听起来正是您所需要的。免费使用级别也适合您的任务。

于 2013-02-22T12:24:58.490 回答
0

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

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

另外,我认为您可以删除:start: mybackend.app从您的backends.yaml

于 2013-02-22T13:33:17.733 回答