python 單一程式例項 實現
目錄
一、說明
之前寫了“Linux shell指令碼單例項模式實現”,python也是日常需要使用的,所以也想來看python中如何實現。
一方面,shell中沒有類和類例項的概念,所以一般說“單例項”都是指“單程式例項”,沒有設計模式中“單例”的概念;另一方面,由於單程式例項和單例都是強調“唯一一份”所以在長時間裡以為他們是相同的一個東西,和shell一樣籠統地稱為單例項就好了。
但現在看來他們不是一回事,“單程式例項”討論的環境是整個記憶體、面向的物件是檔案、結果是要麼幹掉原來的程式新啟一個程式要麼結束當前的程式保留原來的程式。
“單例模式”討論的環境是一個程式內、面向的物件是類,結果是不管你在哪、呼叫多少次返回的都是同一個類例項。也就是說,如果是不同程式,那麼是可以返回不同的類例項的(應該說就沒法返回相同的類例項)。
二、單程式例項實現
2.1 Linux平臺實現--使用標準庫fcntl
linux平臺可以通過python標準庫fcntl來實現鎖
import os
import time
import fcntl
class Test():
# 此函式用於獲取鎖
def _get_lock(self):
file_name = os.path.basename(__file__)
# 為了統一按linux的習慣放到/var/run目錄去
lock_file_name = f"/var/run/{file_name}.pid"
# 是讀還是寫還是什麼模式並不重要,因為只是看能不能獲取檔案鎖而不一定要寫入內容
# 但是這個一定要是成員變數self.fd而不能是區域性變數fd
# 因為實際發現當python發現區域性變數fd不再使用時會將其回收,這就導致後邊再執行時都能獲取到鎖
self.fd = open(lock_file_name, "w")
try:
# #define LOCK_SH 1 /* Shared lock. */ 共享鎖
# #define LOCK_EX 2 /* Exclusive lock. */ 互斥鎖
# #define LOCK_UN 8 /* Unlock. */ 解鎖
# LOCK_NB--非阻塞模式。
# 阻塞模式--獲取不到鎖時一直等待
# 非阻塞模式--獲取不到鎖,直接丟擲異常
fcntl.flock(self.fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
# 將當前程式號寫入檔案
# 如果獲取不到鎖上一步就已經異常了,所以不用擔心覆蓋
self.fd.writelines(str(os.getpid()))
# 寫入的資料太少,預設會先被放在緩衝區,我們強制同步寫入到檔案
self.fd.flush()
except:
print(f"{file_name} have another instance running.")
exit(1)
def __init__(self):
self._get_lock()
def hello_world(self):
print("hello world!")
time.sleep(30)
# 從觀察到的現像看,佔用鎖的程式被關閉後,鎖也就自動釋放了
# 也就是說,其實並不需要在最後自己主動釋放鎖
def __del__(self):
fcntl.flock(self.fd, fcntl.LOCK_UN)
if __name__ == "__main__":
obj = Test()
obj.hello_world()
2.2 通用平臺實現--使用第三方庫portalocker
安裝方法:pip install portalocker
pypi地址:https://pypi.org/project/portalocker/
github地址:https://github.com/WoLpH/portalocker
import os
import time
import portalocker
class Test():
def _get_lock(self):
file_name = os.path.basename(__file__)
# linux等平臺依然使用標準的/var/run,其他nt等平臺使用當前目錄
if os.name == "posix":
lock_file_name = f"/var/run/{file_name}.pid"
else:
lock_file_name = f"{file_name}.pid"
self.fd = open(lock_file_name, "w")
try:
portalocker.lock(self.fd, portalocker.LOCK_EX | portalocker.LOCK_NB)
# 將當前程式號寫入檔案
# 如果獲取不到鎖上一步就已經異常了,所以不用擔心覆蓋
self.fd.writelines(str(os.getpid()))
# 寫入的資料太少,預設會先被放在緩衝區,我們強制同步寫入到檔案
self.fd.flush()
except:
print(f"{file_name} have another instance running.")
exit(1)
def __init__(self):
self._get_lock()
def hello_world(self):
print("hello world!")
time.sleep(30)
# 和fcntl有點區別,portalocker釋放鎖直接有unlock()方法
# 還是一樣,其實並不需要在最後自己主動釋放鎖
def __del__(self):
portalocker.unlock(self.fd)
if __name__ == "__main__":
obj = Test()
obj.hello_world()
三、單例模式實現
3.1 單例模式示例程式碼
import time
import threading
import datetime
class Singleton:
_instance_lock = threading.Lock()
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
with Singleton._instance_lock:
if not hasattr(Singleton, "_instance"):
Singleton._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return Singleton._instance
def main_logic(self):
# 列印自己及當前時間
print(f"instance--{self}\n"
f"now time--{datetime.datetime.now().strftime('%H:%M:%S')}")
time.sleep(10)
if __name__ == "__main__":
obj1 = Singleton()
obj2 = Singleton()
obj1.main_logic()
obj2.main_logic()
3.2 確認單例模式不管例項化多少次都返回同一個物件
執行程式碼,可以看到兩個例項是一樣的
3.3 確認單例模式可以有多個程式例項
我們在最開始說單程式例項和單例模式是不同層次的兩個東西,不能相互代替。為了消除這個疑慮,尤其是單例模式可以代替單程式例項的疑慮,我們來做一下實驗。
在相同時間段內,開啟兩個視窗分別執行程式碼,可以看到兩次都成功了,即使用單例模式的程式碼在記憶體中是可以有多個程式例項的。
相關文章
- Python實現簡單網頁圖片抓取完整程式碼例項Python網頁
- jQuery實現的簡單投票簡單程式碼例項jQuery
- .Net結合PInvoke超簡單實現程式單一例項執行
- EasyUI實現的form表單提交簡單程式碼例項UIORM
- html實現簡單ListViews效果的例項程式碼HTMLView
- javascript實現的動畫效果簡單例項程式碼JavaScript動畫單例
- jQuery實現的自動播放簡單程式碼例項jQuery
- jQuery實現的禁用右鍵選單程式碼例項jQuery
- 使用jquery實現的清空表單元素程式碼例項jQuery
- arguments.callee實現遞迴簡單程式碼例項遞迴
- canvas實現的簡單餅狀圖程式碼例項Canvas
- canvas實現的簡單塗鴉板程式碼例項Canvas
- css實現的div旋轉簡單程式碼例項CSS
- 模擬實現select下拉選單例項程式碼單例
- canvas實現的簡單畫板效果程式碼例項Canvas
- 例項程式碼分享Python實現Linux監控PythonLinux
- python 程式池pool簡單例項薦Python單例
- jQuery實現的動畫簡單例項jQuery動畫單例
- C#實現單例項執行C#單例
- python類例項化如何實現Python
- Java經典例項:實現一個簡單堆疊Java
- css實現梯形程式碼例項CSS
- Python中實現單例模式Python單例模式
- javascript實現的圖片簡單切換程式碼例項JavaScript
- javascript動態實現的表單提交效果程式碼例項JavaScript
- javascript實現的簡單驗證碼效果程式碼例項JavaScript
- 點選回車實現表單提交效果程式碼例項
- javascript實現的清空表單元素內容程式碼例項JavaScript
- js模擬實現select下拉選單程式碼例項JS
- jQuery實現的表單註冊驗證程式碼例項jQuery
- 選項卡方式實現的多角色登陸表單程式碼例項
- css實現對聯程式碼例項CSS
- canvas實現的刮刮樂程式碼例項Canvas
- shell程式設計例項--實現累加程式設計
- javascript實現複製一個陣列程式碼例項JavaScript陣列
- Python的類及單例實現Python單例
- 在Python中實現單例模式Python單例模式
- Python單例模式的實現方式Python單例模式