您的位置:首页 > 编程语言 > Python开发

python 单例模式实现多线程共享连接池

2017-09-02 00:00 267 查看
我们经常使用数据库连接池,但那是有时候有些库并没有实现线程安全的连接池,这个时候,该如何自己封装?多进程和多线程甚至协程模式下,如何控制数据库连接数量或者是socket连接数。这个问题很有意义。

首先,多进程,通常的做法是每个进程实例化一个连接池,为什么不共享一个池,因为多进程和多线程同步的开销不一样,一般三方库都不会支持,但是redis 的库可以,他有些细节不一样。然后多线程共享,只需要将连接放到一个线程安全的容器,比如list 或者queue中。注意多线程和多进程的queue实现方式完全不一样,多线程是使用的mmap。

下面看看一个demo:

import multiprocessing
import threading
import os

def singleton(cls, *args, **kw):
instances = {}#
print "instance is",id(instances)
def _singleton():
#key = str(cls) + str(os.getpid())
key = str(cls)
if key not in instances:
instances[key] = cls(*args, **kw)
return instances[key]

return _singleton
print "instance has been free"

@singleton
class DB(object):
def __init__(self):
self.rabbitmq_pool = self.init_rabbitmq_pool()

def init_rabbitmq_pool(self):
pool = 1#为了简化
return pool

#DB = singleton(DB)

def process1():
print "proc 1 "
db1 = DB()
print "db1 is ", id(db1)

def process2():
print "proc 2 "
db2 = DB()
print "db2 is", id(db2)

if __name__=="__main__":
# print "multiproce "
# pro1 = multiprocessing.Process(target=process1)
# pro2 = multiprocessing.Process(target=process2)
# pro1.start()
# pro2.start()
# pro1.join()
# pro2.join()

print "print thread"
pro1 = threading.Thread(target=process1)
pro2 = threading.Thread(target=process2)
pro1.start()
pro2.start()
pro1.join()
pro2.join()

这部分代码是简化了自己封装的连接池的代码, 主要观察线程单例是否生效,然后那个instance为什么线程能够共享一个连接池。

下面是打印结果:

instance is 140442806348048
print thread
proc 1
db1 is  140442806366352proc 2

db2 is 140442806366352

看到结果,其实很多问题就知道答案了,使用装饰器后, 整个代码段加载的时候,装饰器就已经开始执行,这里的instances 是不会释放的,实际上代码初始化的时候就执行了DB = singleton(DB) ,相当于是 这个闭包是全局变量,又因为dict本身线程安全。所以每次线程用这闭包的时候,获取连接对象都是线程安全的。

这里的单例对多进程是不会生效的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: