Re: [問題] 限制某個function只能被叫到一次

看板Python作者 (貓橘毛發呆雕像)時間4年前發表 (2021/03/16 09:36), 4年前編輯推噓4(4015)
留言19則, 4人參與, 4年前最新討論串3/3 (看更多)
簡單回一下你的誤區。 1.) 的部分請見 https://git.io/JmZ9b 早一點的版本 (<3.6) 是直接用 None 來作 singleton, 在 Python 用 module scope 的 variables 做這種事還蠻常見的。 2.) 的部分 assign 之前要先用 global keyword 宣告成 global 在 multi-threading 的情況下,第 n 個 thread 有極大的可能在 assignment 完成之 前就進到 if condition, 也就是說client 的 creation 會被執行不只一次以上。 這情況蠻常見的,畢竟多數和 db 相關的 libs 都有直接或間接用到 C 會 release GIL 。 解法可參考上面 asyncio 作 thread-local 的方式,如果是想要 thread-global 的話一 般應該是用 multi-lock (一時間想不到哪個 source code 裡面有範例可以看,建議自己試一下) ※ 引述《ddavid (謊言接線生)》之銘言: : ※ 引述《MaR1nlolz (mumimumi)》之銘言: : : 最近遇到個問題,請問一下各位, : : 當執行python app.py時,不論MongoClient()被呼叫幾次,我希望create()只被呼叫 : : , : : 我目前的做法是透過global variable來判斷 : : create()是否被呼叫過,不過global variable用法幾乎都不太建議使用, : : 避免被其他地方改到,想請問各位有沒有比較好的做法,以下是我的程式碼,謝謝 : 我覺得根本問題是你的使用方式出了問題: : 1. instance本質上也不應該global使用 : 2. 你這段Code裡面有過多不必要的包裝 : 先跳過問題1。針對問題2,你會發現這裡的isInit == False幾乎等價於 : instance is None(除非很例外的情況導致MongoClient傳回None),也就是這是多 : 餘的邏輯包裝。最簡單的方式是: : --- mongo.py : from pymongo import MongoClient : instance = None : def create(): : if instance is None: : instance = MongoClient( : 'mongo://127.0.0.1:27017', : maxPoolSize=10 : ) : --- app.py : import mongo : mongo.create() # 之後拿 mongo.instance 來運用 : mongo.create() # 重複呼叫create()會因為instance已經不是None而不會做任何事 : 事實上我想不太到為什麼會導致重複create的狀態,照理說程式應該開頭create : 一次後就只用create好的實體,除非斷線否則再也不會呼叫第二次create才對。你如 : 果把問題一也解決,就會發現連create(或者說整個mongo.py)都是多餘包裝。 : : --- mongo.py : : instance = None : : isInit = False : : def create(): : : mogno = MongoClient('mongo://127.0.0.1:27017', maxPoolSize=10) : : return mogno : : def mongoClient(): : : global isInit, instance : : if isInit == False: : : instance = create() : : isInit = True : : --- app.py : : import mongoClient : : mongoClient() : : mongoClient() : : mongoClient() -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 180.218.219.240 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/Python/M.1615887411.A.F99.html ※ 編輯: zerof (180.218.219.240 臺灣), 03/16/2021 17:41:04

03/16 17:42, 4年前 , 1F
用 mobile app 發文排版有點怪就將就點
03/16 17:42, 1F

03/16 17:58, 4年前 , 2F
lock 的部份關鍵字找『雙重檢查鎖定模式』自己研究一下8
03/16 17:58, 2F

03/17 05:59, 4年前 , 3F
我完全同意你說的內容,但就原Po明白擺出的Code而言,端
03/17 05:59, 3F

03/17 05:59, 4年前 , 4F
出這篇的內容是否有種XY Problem的感覺?XD
03/17 05:59, 4F

03/17 06:03, 4年前 , 5F
比如原問如果明白講了在multi-threading,我自然就不會這
03/17 06:03, 5F

03/17 06:03, 4年前 , 6F
麼答了,但他明白就在問app.py直接call了三次XD
03/17 06:03, 6F

03/17 06:09, 4年前 , 7F
1的部分亦同。當然你的補充都是很正確,我單純在原問有所
03/17 06:09, 7F

03/17 06:09, 4年前 , 8F
補充設定以前就先這麼答,待他若不滿意而有所補充,自然
03/17 06:09, 8F

03/17 06:09, 4年前 , 9F
你就華麗登場了XD
03/17 06:09, 9F
打字沒辦法表示語氣,有覺得冒犯的話先說個抱歉。 就原文的部份,我的看法是 1F 給的 singleton & after_create hook 這兩個關鍵字 就足以解決他的問題了。(當然他自己寫的 code 的 quality 是另一回事) (以他的檔名`app.py` + db initial 的情況,沒意外會是 flask-like 的 web) 基本上我回文主要是基於你的內文 (會提到 multi-thread 的部份,一來是 link 中 的 `_RunningLoop` 是繼承自 threading.local ,二來是你原文內對 create method 「想不太到會導致重複」的補充說明。) btw, link 稍微更新了一下,之前好像縮的時候沒縮到行號,在 L:694 左右。 當然我也不單純是無聊想糾正你,在假設他是用 flask 的情況下,在 local debug 的 時候就可以用 `app.run(threaded=True)` 來模擬(?) production 的情況,在文件內提 供的多數 deploy options (gevent, twisted, gunicorn...) 內都會有 multithreading 的 context (如果是用 Sanic 的話就更複雜了但我想會 Sanic 的不會問這種問題) 這些內容基本上用他用的 framework 當 keyword 加上 singleton/after_create hook 都會有些類似的 stackoverflow 可以研究參考。 (不過 flask 沒有 after_create hook ,當然你沒說我也沒必要特別提供正確的... 呃不是,就 keyword 自己研究下先搞清楚自己在問什麼說不定就解決了嘛) 我自己的想法很簡單,你懶我也懶,資訊給得少我就回少一點…會在網路上問問題的 人我自己是歸類成兩種,一種會符合 SSCCE(http://www.sscce.org/ ),要回問題就很 快;另一種就是給的通常都是片段的資訊,有時候自己也不知道自己在問什麼 (這種連 吐嘈都覺得好懶啊...)。 除此之外的共通點就是,會再給更多資訊的很少。 (有時候是自己想通了,有時候是 看了別人給的建議反而做了別的選擇之類的 blahblah) 這種行為就像是在丟 UDP 的 packets 一樣,沒有下文。 (反正我問題解了就好,回個感謝或是什麼之類的就再說) 也無所謂啦,反正我也是那種興致來了就回個文, keywords 都有大家自己研究研究 大概是這樣。最後還是回到一開頭那句,看文的覺得有冒犯就抱歉惹誤會誤會>< ※ 編輯: zerof (180.218.219.240 臺灣), 03/18/2021 02:31:29

03/18 08:04, 4年前 , 10F
完全沒問題!:)
03/18 08:04, 10F

03/18 18:57, 4年前 , 11F
誤區是哪裡的方言?
03/18 18:57, 11F

03/19 00:07, 4年前 , 12F
誤區一詞常見於商院相關書籍,英文應該是用 area of misund
03/19 00:07, 12F

03/19 00:07, 4年前 , 13F
erstanding; 台文比較接近的詞應該是 誖誤 (但實際上和誖誤
03/19 00:07, 13F

03/19 00:07, 4年前 , 14F
的意思有些出入) 中文有蠻多詞在萌典/教育部辭典是查不到
03/19 00:07, 14F

03/19 00:07, 4年前 , 15F
的。至於是否為中國慣用詞彙,希望你可以研究一下 我也蠻想
03/19 00:07, 15F

03/19 00:07, 4年前 , 16F
知道的 ;)
03/19 00:07, 16F

03/19 09:09, 4年前 , 17F
誖誤不是有些出入,是完全不同吧...
03/19 09:09, 17F

03/19 09:09, 4年前 , 18F
就單純積非成是而已
03/19 09:09, 18F

03/19 20:28, 4年前 , 19F
個人建議就還是...查查字典
03/19 20:28, 19F
文章代碼(AID): #1WK7mp-P (Python)
文章代碼(AID): #1WK7mp-P (Python)