我们经常使用数据库连接池,但那是有时候有些库并没有实现线程安全的连接池,这个时候,该如何自己封装?多进程和多线程甚至协程模式下,如何控制数据库连接数量或者是socket连接数。这个问题很有意义。
该文章后续仍在不断的更新修改中, 请移步到原文地址http://dmwan.cc
首先,多进程,通常的做法是每个进程实例化一个连接池,为什么不共享一个池,因为多进程和多线程同步的开销不一样,一般三方库都不会支持,但是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本身线程安全。所以每次线程用这闭包的时候,获取连接对象都是线程安全的。
这里的单例对多进程是不会生效的。
原文地址:https://my.oschina.net/u/2950272/blog/1528034