我正在讀取GZipped LXML文件並嘗試將產品條目寫入數據庫模型。以前我遇到了本地內存問題,這些問題通過SO(question)上的幫助解決。現在,我得到的一切工作,並部署它,但是我得到以下錯誤在服務器上:GAE Python LXML - 超出軟內存限制
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
start: mybackend.app
你經常需要從導入數據xml文件。如果偶爾您會發現使用remote_api更容易,並在本地處理文件並直接寫入數據存儲區。然後完整可以像你本地機器可以處理的一樣大。 – 2013-02-23 11:36:05還要注意'德爾C'可能什麼都不會做,除非你明確調用GC.Collect()作爲東西不會可能會被收集了相當一段時間。另外,也要看看你的代碼,你必須讀文件/ StringIO的,XML(這是StringIO的包裝的C版本),然後全面分析樹。你說這是80MB的壓縮文件,至少有一份你還沒有加過樹。您可以考慮使用拉解析策略,這將意味着你沒有在內存中全面分析樹副本以及字符串。 – 2013-02-23 11:41:44
謝謝Tim的意見。是的,我確實考慮過remote_api選項,但是在某些時候,這個腳本將以每日運行速度運行,這就是我選擇當前設置的原因。我會研究你對拉分析策略的建議,看看它能否改善性能。再次感謝! – Vincent 2013-02-23 16:14:59