星期四, 5月 10, 2018

Django 節省記憶體的一些紀錄之二

這篇會順帶提一些提高效能的紀錄。

strftime

datetime.strftime 可以將日期時間格式化為需要的字串,但是,在經過 profiling 以後,我發現呼叫這個函式相當的花時間。在網路上搜尋以後,發現有人在 stackoverflow 上問相似的問題,有人回答說改用 python 的 string format 就可以大大的提高效能。
# 原作法
from datetime import datetime
dt = datetime.now()
dt.strftime("%Y/%m/%d")  # slower
"{:04d}/{:02d}/{:02d}".format(dt.year, dt.month, dt.day)  # Fast!!

JSONEncoder.iterencode

這是在Use StreamingHttpResponse by default for JSON 這個 gist 上看到的,裏面使用了 JSONEncoder.iterencode 搭配 StreamingHTTPResponse 處理。一般來說,在輸出為 JSON 時,都是整個物件或資料丟給 json.dumps(),但這樣在處理大量資料的情況時,其實是有可能佔用大量記憶體的。Python json 模組的 JSONEncoder 提供了 iterencode() 函式,iterncode() 會回傳 generator 回來,之前有提到使用 generator 可以確保在使用到的時候,才將值回傳出來,可以避免佔用過多的記憶體。再加上 StreamingHTTPResponse/HTTPResponse 的 content 都支援使用 generator,這樣就可以節省大量記憶體了。

日期時間時區的轉換

本來我是使用 Arrow 在處理時區的轉換,但是,在 profiling 以後,發現這個步驟會花掉蠻多時間,於是看過 Arrow 的原始碼以後,發現 Arrow 只是使用 python datetime 模組裡面的函式在做,所以將原本時區轉換的部份改寫掉,就大幅提升速度了。

from arrow import Arrow
from dateutil import tz
from django.utils import timezone

dt = timezone.now()  # utc time
new_timezone = tz.gettz('Asia/Taipei')  # get local timezone
new_local_time_1 = Arrow.fromdatetime(dt).to(new_timezone).datetime  # slower
new_local_time_2 = dt.astimezone(new_timezone)  # Fast!!

沒有留言: