咱們常常使用數據庫鏈接池,但那是有時候有些庫並無實現線程安全的鏈接池,這個時候,該如何本身封裝?多進程和多線程甚至協程模式下,如何控制數據庫鏈接數量或者是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