python 單例模式實現多線程共享鏈接池

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

相關文章
相關標籤/搜索