iT邦幫忙

2021 iThome 鐵人賽

DAY 23
0
永豐金融APIs

深入解析 Shioaji API系列 第 23

Day 23 - 重覆呼叫shioaji.Shioaji()產生的記憶體問題

因為看到有人反應,重覆登出登入,會造成記憶體使用量增加,這實在是讓人太好奇了,所以就想來實測一下。但因為反應問題的人也沒有提供程式內容,所以只是自己猜可能的程式內容

測試程式及結果

測試程式範例:

import os, psutil, gc, time
import shioaji as sj
from dotenv import load_dotenv

load_dotenv('D:\\python\\shioaji\\.env') #讀取.env中的環境變數

process = psutil.Process(os.getpid())
print(f'mem usage as start: {process.memory_info()[0]/float(2 ** 20)}kb')

for i in range(5):
    api = sj.Shioaji(simulation=True)
    print(f'({i})mem usage at api initial: {process.memory_info()[0]/float(2 ** 20)}kb')
    api.login(
        person_id='PAPIUSER01', 
        passwd='2222'
    )
    print(f'({i})mem usage at api.login: {process.memory_info()[0]/float(2 ** 20)}kb')
    api.logout()
    time.sleep(10) #登出後,等待10秒再進行登入,防止出錯

del api
gc.collect()
print(f'mem usage after del api: {process.memory_info()[0]/float(2 ** 20)}kb')

上面用for in的方式重覆進行5次初始化、登入及登出動作,來測試是否有產生RAM使用量增加的情況,在測試時發現若登入的環境是測試環境,雖然RAM使用量有增加,但其實不明顯。而上面這個範例,是用測試環境及帳號進行測試,若是正式環境,只需傳入自己的帳號密碼,並且在初始化時,不設定simulation=True即可。
測試結果如下(單位:KB):

程式點 windows&正式環境 windows&測試環境 ubuntu&正式環境 ubuntu&測試環境
start 33.98828125 33.84375 34.59765625 34.5
0-initial 38 37.89453125 37.98828125 37.84765625
0-login 126.1132813 39.3671875 72.94140625 39.03515625
1-initial 227.5351563 40.23828125 203.6210938 39.87109375
1-login 219.4492188 40.125
2-initial 409.7734375 41.18359375 225.5703125 40.3828125
2-login 471.53125 41.90234375 239.6914063 40.63671875
3-initial 591.7265625 42 264.2929688 40.63671875
3-login 642.1875 42.72265625 286.9375 40.890625
4-initial 775.7148438 42.84765625 328.703125 41.1484375
4-login 844.2929688 43.55859375 354.390625 41.40234375
del & gc 956.984375 42.75 494.125 41.52734375

由測試結果可以看到,的確這樣的寫法是會增加許多RAM的使用量,不過在Linux環境中,增加的量不像在Windows下那樣誇張。而測試環境的部份,竟然差異不大,這可能要請開發團隊看才能知道為何有這差異。

問題原因&解決方式

其實RAM使用量增加主要是因為重覆執行sj.Shioaji()進行初始化動作所造成,雖然執行login()後,RAM使用量也會增加,但並沒有像執行sj.Shioaji()時增加那麼多。解決方式可分為下列2種:
1.sj.Shioaji()移至迴圈或是function外層,避免重覆執行
2.在login時,傳入fetch_contract=False,即不執行fetch_all_contract動作,預先抓所有的contract
我個人比較便好1,因為只需要將原本的程式做一點小調整即可。
第2種方式雖然也可以,但是Contract物件經常會被使用到,若指定fetch_contract=False,則無法透過api取得Contract內容,也就要考慮用object serialization先將Contract物件儲存起來,要用的時候再做讀取的動作。


上一篇
Day 22 - Blocking & Non-blocking Mode
下一篇
Day 24 - Shiaoji.Login踩坑經驗及修正
系列文
深入解析 Shioaji API30

尚未有邦友留言

立即登入留言