Python import模塊的緩存問題解決方案
在使用django開發的平臺中,支持用戶自定義函數,但是每次用戶進行修改編輯後,該模塊內容已更改,然後重新導入該模塊,但是Python 會認為“我已經導入瞭該模塊,不需要再次讀取該文件”,所以更改將無效。
因此,每次更改文件的內容時,都必須退出並重新啟動Django。
使用python開發後臺服務程序的時候,每次修改代碼之後都需要重啟服務才能生效比較麻煩
要解決這個問題,有以下幾種方式:
最簡單、最有效的方法:重新啟動 Django。但是,這也有缺點,特別是丟失瞭 django名稱空間中存在的數據以及其他導入模塊中的數據。
對於簡單的情況,可以使用 Python 的reload()函數。在許多情況下,在編輯一個模塊之後使用
reload()函數就足夠滿足需求。
這裡主要是介紹第二種方式:
reload()是 Python 提供的內置函數,在不同的 Python 版本中有不同的表現形式:
在 Python 2.x 中,reload()是內置函數。
在 Python 3.0 – 3.3 中,可以使用imp.reload(module)。
在 Python 3.4 中,imp 已經被廢棄,取而代之的是importlib。
Python2.7可以直接用reload():
python2 內置函數reload(module)
Python3可以用下面幾種方法:
方法一:基本方法
from imp import reload reload(module)
方法二:
import imp imp.reload(module)
方法三:
import importlib importlib.reload(module)
方法四:
from importlib import reload reload(module)
說明:
module 必須是已經成功導入的模塊
模塊被加載到內存以後,更改文件內容,已經運行的程序不會生效的,可通過reload重新加載。
導入是一個開銷很大的操作。
python中緩存模塊的一些用法
一.問題描述
有時候可能需要緩存一些 成員方法的值, 可能成員方法的計算比較耗時,有時候不希望重復調用計算該值, 這個時候就可以緩存該值.
查瞭一下標準庫 有 functools.lru_cache 有一個 lru_cache 可以緩存成員函數的值,
#!/usr/bin/env python3 # -*- coding: UTF-8 -*- """ @author: Frank @contact: [email protected] @file: test_lru_cache.py @time: 2018/9/8 下午8:55 """ import time from functools import lru_cache class Model: @lru_cache(maxsize=10) def calculate(self, number): print(f'calculate({number}) is running,', end=' ') print('sleep 3s ') time.sleep(3) return number * 3 if __name__ == '__main__': model = Model() for i in range(5): print(model.calculate(i)) for i in range(5): print(model.calculate(i))
結果如下:
calculate(0) is running, sleep 3s
0
calculate(1) is running, sleep 3s
3
calculate(2) is running, sleep 3s
6
calculate(3) is running, sleep 3s
9
calculate(4) is running, sleep 3s
12
0
3
6
9
12
從結果開出來, 第二次計算的時候 , 就沒有計算 而是通過緩存取值, 所以成員方法隻計算瞭一次.
lru_cache 可以指定 max_size 緩存的大小, typed bool 如果為True, 代表不同類型分別緩存. 如果達到max_size 淘汰策略是LRU, LRU是Least Recently Used的縮寫,即最近最少使用,常用於頁面置換算法.
二 第三方的模塊
第三方的模塊cachetools 已經提供瞭很多緩存策略,直接拿來用一下.
來看下面的例子.
1 來看一個緩存成員方法例子
#!/usr/bin/env python3 # -*- coding: UTF-8 -*- """ @author: Frank @contact: [email protected] @file: test_cache.py @time: 2018/9/8 下午12:59 pip install cachetools https://docs.python.org/3/library/operator.html 緩存成員方法的值 cachetools 已經實現好瞭, 直接用就可以瞭. """ from operator import attrgetter import time from cachetools import LRUCache,RRCache , cachedmethod class Model: def __init__(self, cachesize): self.cache = LRUCache(maxsize=cachesize) @cachedmethod(attrgetter('cache')) def get_double_num(self, num): """ return 2* num""" print(f'get_double_num({num}) is running') time.sleep(2) return num * 2 model = Model(cachesize=10) print(model.get_double_num(10)) print(model.get_double_num(10)) print(model.get_double_num(10)) print(model.get_double_num(10)) print(model.get_double_num(10)) print(model.get_double_num(10))
結果如下:
get_double_num(10) is running
20
20
20
20
20
20
Process finished with exit code 0
可以看出, 值計算一次 函數,第二次走的是緩存. 非常好用. 在初始化方法裡面構造一個緩存對象, 之後用 cachedmethod 修飾成員函數,同時 用attrgetter(‘cache’) 把cache 拿到就可以用瞭.
實際上 cachetools 實現瞭很多緩存策略,具體緩存策略可以參考下面的鏈接.
'Cache', 'LFUCache', 'LRUCache', 'RRCache', 'TTLCache',
‘cached’, ‘cachedmethod’ 這兩個分別用來修飾 函數和成員方法的.
2 來看一個 緩存函數
# 緩存 函數的值 from cachetools import cached @cached(cache={}) def fib(n): print((f'fib({n}) is running.')) return n if n < 2 else fib(n - 1) + fib(n - 2) for i in range(20): print('fib(%d) = %d' % (i, fib(i)))
@cached(cache={}) def fun(n): print(f'fun({n}) is runnnig.') time.sleep(3) return n ** 2 if __name__ == '__main__': for _ in range(5): print(fun(4))
如果cache = None , 表示不緩存,該計算結果.
結果如下:
fun(4) is runnnig.
16
16
16
16
16
直接導入 cached 裡面 傳入一個字典就可以瞭,用起來也比較方便.
實現分析:
緩存思路大致是一樣的, 首先先把參數hash 一下生成一個key, 然後看key 是否在自己的緩存裡,不在就計算方法(函數),之後把key和對應value 放到自己的子弟那裡面. 如果下一次計算該值,生成一個key 看是否在 自己的字典裡面,如果在直接返回即可. 當然這是基本的思路, 裡面還有用到 緩存淘汰策略, 多線程是否要加鎖,等比較復雜的問題.
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- python 模塊重載的五種方法
- python 動態導入模塊實現模塊熱更新的方法
- 簡單談談Python中的模塊導入
- Python多線程以及多線程中join()的使用方法示例
- Python入門基礎之import機制