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網頁
- 例項程式碼分享Python實現Linux監控PythonLinux
- html實現簡單ListViews效果的例項程式碼HTMLView
- python類例項化如何實現Python
- Python中實現單例模式Python單例模式
- Python物件導向多型實現原理及程式碼例項Python物件多型
- Python的類及單例實現Python單例
- Python實現遠端埠監控例項Python
- 【深度學習基礎-11】簡單線性迴歸(下)--例項及python程式碼實現深度學習Python
- Python訪問小程式簡單方法程式碼例項詳解Python
- Python 5種方法實現單例模式Python單例模式
- HTML 使用表單標籤實現註冊頁面的例項程式碼HTML
- 例項QT程式 —— Qt單例不規則介面程式QT單例
- vuejs實現新增tag標籤程式碼例項VueJS
- 用Python實現設計模式——單例模式Python設計模式單例
- Python單例模式(Singleton)的N種實現Python單例模式
- HTML6實現摺疊選單與手風琴選單的例項程式碼HTML
- Python專案實戰例項Python
- python 連線mongodb實現增刪改查例項PythonMongoDB
- 透過程式碼例項簡單瞭解Python sys模組Python
- MyCat分片:水平拆分例項解析和程式碼實現!
- python如何實現單例模式?常用方法彙總!Python單例模式
- Python scrapy增量爬取例項及實現過程解析Python
- JavaScript 表單驗證程式碼例項JavaScript
- 正則實現個位數補零程式碼例項
- 單例模式 – 單例登錄檔與 Spring 實現單例剖析單例模式Spring
- 關於python單例的常用幾種實現方法Python單例
- Python 實現工廠模式、抽象工廠,單例模式Python模式抽象單例
- python socket例項Python
- python例項1Python
- PHP實現單例模式PHP單例模式
- golang實現單例模式Golang單例模式
- 用Rust實現單例Rust單例
- golang如何實現單例Golang單例
- Rust實現單例模式Rust單例模式
- 淡入淡出效果簡單程式碼例項
- Python簡單函式迴圈綜合例項Python函式
- 實現單項鍊表