单例
- 单例在多线程下,可以保证全局唯一,但在多进程下呢?
- 子进程不共享父进程的变量
所以,每个进程都维护着一个自己的单例。
验证
创建appserver
以flask为例,以包的形式创建一个单例
# view.py--------------------------------------------------------------
from single import indexer
from flask import Blueprint
from flask import jsonify
from flask import request
view_bp = Blueprint("view_bp", __name__)
@view_bp.route("/get")
def get_name():
print("lock", id(indexer.mu))
print("indexer", id(indexer))
return jsonify({"code": 1, "msg": indexer.get()})
@view_bp.route("/set")
def set_name():
print("lock", id(indexer.mu))
print("indexer", id(indexer))
return jsonify({"code": 1, "msg": indexer.set(request.args.get("name"))})
# single.py ----------------------------------------------------------------------
from multiprocessing import Lock
class __Indexer:
names = set()
def __init__(self):
self.mu = Lock()
def set(self, name):
self.names.add(name)
def get(self):
return self.names.pop()
indexer = __Indexer()
# main.py -----------------------------------------------------------------------
from flask import Flask
from view import view_bp
app = Flask(__name__)
app.register_blueprint(view_bp)
if __name__ == '__main__':
# 多进程启动
app.run("0.0.0.0", port=8000, processes=4)
用gunicorn去替换flask的werkzurg(也可以用uwsgi去替换)
# gunicorn.conf
bind = "0.0.0.0:5000"
# 4个worker
workers = 4
backlog = 2048
pidfile = "log/gunicorn.pid"
# accesslog = "log/access.log"
# errorlog = "log/debug.log"
timeout = 600
debug=False
capture_output = True

假设
如果indexer全局唯一,那么names全局唯一,只要一次set一次get,程序不会报错
实操
set-get一次后程序奔溃,并且可以看到打印出来的内存地址两次不相同

结论:开启的四个进程,每个进程中都有自己的indexer,并不是唯一。
将set替换为Manger().List()
from multiprocessing import Lock
from multiprocessing import Manager
class __Indexer:
# names = set()
names = Manager().list()
def __init__(self):
self.mu = Lock()
def set(self, name):
# self.names.add(name)
self.names.append(name)
def get(self):
return self.names.pop()
indexer = __Indexer()
再次验证,依旧会显示从empty中取值

使用类方法实现单例(不考虑高并发)
from multiprocessing import Lock
from multiprocessing import Manager
class _Indexer:
names = set()
# names = Manager().list()
instance = None
@classmethod
def new(cls):
if cls.instance is None:
cls.instance = cls()
return cls.instance
else:
return cls.instance
def __init__(self):
self.mu = Lock()
def set(self, name):
self.names.add(name)
# self.names.append(name)
def get(self):
return self.names.pop()
# indexer = _Indexer()
indexer = _Indexer.new()

将indexer移出去
# from single import indexer
from single import _Indexer
from flask import Blueprint
from flask import jsonify
from flask import request
view_bp = Blueprint("view_bp", __name__)
indexer = _Indexer.new()
依旧报错,相当于将name随机放到了某个进程下的names当其他进程去取时,自然会报错。

重新打开Manager()

结论
到目前为止,可以确定,每一个进程都有自己的indexer
加锁
普通锁
放到single.py
from multiprocessing import Lock
from multiprocessing import Manager
mu = Lock()
class _Indexer:
names = set()
# names = Manager().list()
instance = None
@classmethod
def new(cls):
print("global",mu)
with mu:
if cls.instance is None:
cls.instance = cls()
return cls.instance
else:
return cls.instance
def __init__(self):
self.mu = Lock()
def set(self, name):
self.names.add(name)
# self.names.append(name)
def get(self):
return self.names.pop()
# indexer = _Indexer()
# indexer = _Indexer.new()

刚启动,就显示创建了4个锁。。。。
放到main.py
from flask import Flask
from view import view_bp
from multiprocessing import Lock
app = Flask(__name__)
app.register_blueprint(view_bp)
if __name__ == '__main__':
mu = Lock()
app.run("0.0.0.0", port=8000, processes=4)

循环导入,崩溃
Manager().Lock()
from multiprocessing import Lock
from multiprocessing import Manager
# mu = Lock()
mu = Manager().Lock()
class _Indexer:
names = set()
# names = Manager().list()
instance = None
@classmethod
def new(cls):
print(mu)
with mu:
if cls.instance is None:
cls.instance = cls()
return cls.instance
else:
return cls.instance
def __init__(self):
self.mu = Lock()
def set(self, name):
self.names.add(name)
# self.names.append(name)
def get(self):
return self.names.pop()
# indexer = _Indexer()
# indexer = _Indexer.new()
也是创建了四个锁

依旧不是全局唯一

到最后,我自己也乱了,,,,
总之就是,httpserver进程间数据不共享,单例也不是单例,如果要创建单例,应该用fd是否存在去创建,这样所有的进程都可以"看得到这个fd锁"
import os
def lock():
while True:
if os.path.exists("./mutex.lock"):
return False
else:
with open("./mutex.lock", "wb") as fd:
pass
return True
def unlock():
os.remove("./mutex.lock")


![[附源码]Python计算机毕业设计Django学生疫情防控信息填报系统](https://img-blog.csdnimg.cn/86746e2939044dd897549c1beb9e949f.png)









![Matplotlib入门[07]——修改默认设置](https://img-blog.csdnimg.cn/e06ed3052bd94d6797c68b322dcc3f04.png)






