咱们常常使用数据库链接池,但那是有时候有些库并无实现线程安全的链接池,这个时候,该如何本身封装?多进程和多线程甚至协程模式下,如何控制数据库链接数量或者是socket链接数。这个问题颇有意义。python
该文章后续仍在不断的更新修改中, 请移步到原文地址http://dmwan.ccredis
首先,多进程,一般的作法是每一个进程实例化一个链接池,为何不共享一个池,由于多进程和多线程同步的开销不同,通常三方库都不会支持,可是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为何线程可以共享一个链接池。bash
下面是打印结果:多线程
instance is 140442806348048 print thread proc 1 db1 is 140442806366352proc 2 db2 is 140442806366352
看到结果,其实不少问题就知道答案了,使用装饰器后, 整个代码段加载的时候,装饰器就已经开始执行,这里的instances 是不会释放的,实际上代码初始化的时候就执行了DB = singleton(DB) ,至关因而 这个闭包是全局变量,又由于dict自己线程安全。因此每次线程用这闭包的时候,获取链接对象都是线程安全的。闭包
这里的单例对多进程是不会生效的。 socket