python进阶21再识单例模式

父子进程内部变量是否可以直接共享,当然不是,需要“特殊加工”下才行。
那么在web开发中的单例模式,是真正的全局唯一的单例么?自然也是
惭愧,自己用单例还是比较多的,还真是第一次注意到这一点。之前使用时,想当然的以为就是(应用程序级别)全局唯一的,譬如java的类里的static,python模块中的定义的对象(只会加载一次),但严格说,都是错误的用法(侥幸的是,尚未出现由此导致的Bug,大概率因为自己用单例大多是为了保存静态内容(只查,不改),加速查询而已。并未用来做全局性统计)。

如何理解单例模式中的唯一性?

根据定义,一个类只允许创建唯一的一个对象,对象的唯一作用范围是什么?是指进程内只允许创建一个,还是线程内只允许创建一个?答案是前者,也就是说单例创建的对象是进程内唯一的。怎么理解呢,我们编写的程序最终执行时,都是操作系统先启动一个进程,然后将程序(可执行文件)加载到内存地址空间,一条一条执行其中的指令,遇到类的实例化时就分配内存地址给新的对象,如果该进程 fork 了另外的新进程,操作系统会分配新的地址空间,并将原来的进程空间的所有内容全部复制到新的地址空间,包括已经实例化的对象,单例类在老进程内只有一个,在新进程内也只有一个,也就是说进程内唯一,进程间不唯一

如何实现线程唯一的单例?

单例类默认是进程内只存在唯一的对象,进程又包含一个或多个线程,这也意味着在线程间也是唯一的,那么如何改进,实现线程内唯一,线程间不唯一的单例呢?其实也非常简单,我们只需借助一个字典,将线程 ID 作为键,单例类对象作为值进行存储,这样就可以做到相同的线程对应相同的单例对象。

如何在集群环境中实现单例?

刚才说了进程内唯一,线程内唯一,现在提到的集群环境中实现单例,就是集群内唯一,实质就是进程间唯一。进程之间是不共享内存的,那就需要借助外部存储来实现,比如文件或数据库,或像 redis 一样具有存储功能的中间件。我们把单例类对象通过序列化保存在外部存储,进程在使用这个单例类对象时先访问外部存储,然后反序列化成对象使用,使用完成后在序列化保存在外部存储。
为了保证任何时刻,在进程之间只有一份对象存在,一个进程在反序列化获取对象之后需要对对象加锁,防止其他进程获取该对象,使用完后序列化保存到外部存储,然后显式的从内存中删除对象(instance = None),并释放锁。

django之全局变量

序列化存储:python 有 zodb
django-solo helps working with singletons: things like global settings that you want to edit from the admin site.
python 的 web 应用都需要用 uwsgi 或 gunicorn 之类的多进程服务器,进程之间的全局变量实际上是相互隔离的。所有只能用 redis 或 django 的 cache 这种公共存储。
最省事是用 Django 的缓存

参考

你是否真的理解单例模式?:https://www.ershicimi.com/p/7cb8aab37c6653a09b8e5b187739af67
uwsgi多进程配合kafka-python消息无法发送:https://www.cnblogs.com/MnCu8261/p/10482031.html
django 中如何维护一个全局变量:https://www.v2ex.com/t/504042

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×