hash遊戲競猜系統開發方案丨雜湊HASH遊戲競猜系統開發方案/(原始碼部署)

Tg_StPv888發表於2023-03-28

使用模組其實,Python 的模組就是天然的單例模式,因為模組在第一次匯入時,會生成 .pyc 檔案,當第二次匯入時,就會直接載入 .pyc 檔案,而不會再次執行模組程式碼。

因此,我們只需把相關的函式和資料定義在一個模組中,就可以獲得一個單例物件了。

如果我們真的想要一個單例類,可以考慮這樣做:class Singleton(object):(開發)找(銘籽)

    def foo(self):

        pass

singleton = Singleton()

將上面的程式碼儲存在檔案 mysingleton.py 中,要使用時,直接在其他檔案中匯入此檔案中的物件,這個物件即是單例模式的物件

from mysingleton import singleton

使用裝飾器

def Singleton(cls):

    _instance = {}

    def _singleton(*args, **kargs):

        if cls not in _instance:

            _instance[cls] = cls(*args, **kargs)

        return _instance[cls]

    return _singleton

@Singleton

class A(object):

    a = 1

    def __init__(self, x=0):

        self.x = x

a1 = A(2)

a2 = A(3)

使用類

class Singleton(object):

    def __init__(self):

        pass

    @classmethod

    def instance(cls, *args, **kwargs):

        if not hasattr(Singleton, "_instance"):

            Singleton._instance = Singleton(*args, **kwargs)

        return Singleton._instance

一般情況,大家以為這樣就完成了單例模式,但是當使用多執行緒時會存在問題:

class Singleton(object):

    def __init__(self):

        pass

    @classmethod

    def instance(cls, *args, **kwargs):

        if not hasattr(Singleton, "_instance"):

            Singleton._instance = Singleton(*args, **kwargs)

        return Singleton._instance

import threading

def task(arg):

    obj = Singleton.instance()

    print(obj)

for i in range(10):

    t = threading.Thread(target=task,args=[i,])

    t.start()

程式執行後,列印結果如下:

<__main__.Singleton object at 0x02C933D0>

<__main__.Singleton object at 0x02C933D0>

<__main__.Singleton object at 0x02C933D0>

<__main__.Singleton object at 0x02C933D0>

<__main__.Singleton object at 0x02C933D0>

<__main__.Singleton object at 0x02C933D0>

<__main__.Singleton object at 0x02C933D0>

<__main__.Singleton object at 0x02C933D0>

<__main__.Singleton object at 0x02C933D0>

<__main__.Singleton object at 0x02C933D0>

看起來也沒有問題,那是因為執行速度過快,如果在 __init__ 方法中有一些 IO 操作,就會發現問題了。

下面我們透過 time.sleep 模擬,我們在上面 __init__ 方法中加入以下程式碼:

def __init__(self):

    import time

    time.sleep(1)

重新執行程式後,結果如下:

<__main__.Singleton object at 0x034A3410>

<__main__.Singleton object at 0x034BB990>

<__main__.Singleton object at 0x034BB910>

<__main__.Singleton object at 0x034ADED0>

<__main__.Singleton object at 0x034E6BD0>

<__main__.Singleton object at 0x034E6C10>

<__main__.Singleton object at 0x034E6B90>

<__main__.Singleton object at 0x034BBA30>

<__main__.Singleton object at 0x034F6B90>

<__main__.Singleton object at 0x034E6A90>

問題出現了!按照以上方式建立的單例,無法支援多執行緒。

解決辦法:加鎖!未加鎖部分併發執行,加鎖部分序列執行,速度降低,但是保證了資料安全。

import time

import threading

class Singleton(object):

    _instance_lock = threading.Lock()

    def __init__(self):

        time.sleep(1)

    @classmethod

    def instance(cls, *args, **kwargs):

        with Singleton._instance_lock:

            if not hasattr(Singleton, "_instance"):

                Singleton._instance = Singleton(*args, **kwargs)

        return Singleton._instance

def task(arg):

    obj = Singleton.instance()

    print(obj)

    

for i in range(10):

    t = threading.Thread(target=task,args=[i,])

    t.start()

time.sleep(20)

obj = Singleton.instance()

print(obj)

列印結果如下:

<__main__.Singleton object at 0x02D6B110>

<__main__.Singleton object at 0x02D6B110>

<__main__.Singleton object at 0x02D6B110>

<__main__.Singleton object at 0x02D6B110>

<__main__.Singleton object at 0x02D6B110>

<__main__.Singleton object at 0x02D6B110>

<__main__.Singleton object at 0x02D6B110>

<__main__.Singleton object at 0x02D6B110>

<__main__.Singleton object at 0x02D6B110>

<__main__.Singleton object at 0x02D6B110>

這樣就差不多了,但是還是有一點小問題,就是當程式執行時,執行了 time.sleep(20) 後,下面例項化物件時,此時已經是單例模式了。

原創宣告,本文系作者授權騰訊雲開發者社群發表,未經許可,不得轉載。

如有侵權,請聯絡 cloudcommunity@tencent.com 刪除。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70016646/viewspace-2942052/,如需轉載,請註明出處,否則將追究法律責任。

相關文章