Skip to content

Instantly share code, notes, and snippets.

@p208p2002
Last active July 23, 2022 01:33
Show Gist options
  • Save p208p2002/590d5e1c5878a27cd8340a2251e08155 to your computer and use it in GitHub Desktop.
Save p208p2002/590d5e1c5878a27cd8340a2251e08155 to your computer and use it in GitHub Desktop.
#python #singleton

Python中單例模式的應用

建構一個大型AI系統,常常會在許多地方呼叫模型,但是模型佔用資源龐大,不可以無限制的實例。

當然可以透過傳遞的方式將模型傳給各別模組,但是可能會變成一個傳遞地獄;或是透過約定一個全域變數的方式來達成,這方法可行但仍然不夠好。

這時候就輪到單例模式登場了,單例模式只允許同個類別存在一個實例,若多次執行類別實例動作,則返回已經實例化的類別。沒有傳遞與管理全域變數的問題!

下面的範例使用一個裝飾器(decorator)來達到單例目的,而從輸出可以發現我們成功避免多次實例同個類別。

範例

from transformers import AutoTokenizer, AutoModelForMaskedLM
from time import time


def singleton(class_):
    instances = {}

    def getinstance(*args, **kwargs):
        if class_ not in instances:
            instances[class_] = class_(*args, **kwargs)
        return instances[class_]
    return getinstance


class BigModel():
    def __init__(self):
        self.tokenizer = AutoTokenizer.from_pretrained("albert-base-v2")

        # instance a big model
        self.model = AutoModelForMaskedLM.from_pretrained("albert-base-v2")


@singleton
class SingletonBigModel(BigModel):
    """
    當類別存在則返回已經實例過後的類別
    """
    pass


if __name__ == "__main__":
    for i in range(3):
        start_time = time()
        model = BigModel()
        print(f"i: {i}, {id(model)}, {round(time() - start_time,5)}/s")

    for j in range(3):
        start_time = time()
        model = SingletonBigModel()
        print(f"j: {j}, {id(model)}, {round(time() - start_time,5)}/s")

輸出

i: 0, 4694351680, 10.1407/s
i: 1, 4728420672, 10.21932/s
i: 2, 4694351680, 10.03433/s

j: 0, 4310527856, 11.0801/s
j: 1, 4310527856, 0.0/s
j: 2, 4310527856, 0.0/s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment