因為看到有人反應,重覆登出登入,會造成記憶體使用量增加,這實在是讓人太好奇了,所以就想來實測一下。但因為反應問題的人也沒有提供程式內容,所以只是自己猜可能的程式內容
測試程式範例:
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物件儲存起來,要用的時候再做讀取的動作。