Python multiprocessing模塊manager封裝簡(jiǎn)述

眾所周知撒会,Python是使用偽多線程運(yùn)行的嘹朗。這導(dǎo)致在多核情況下,CPU并沒(méi)有被良好地利用起來(lái)诵肛。為了提高性能屹培,我們一般會(huì)選擇多進(jìn)程進(jìn)行工作。

進(jìn)程之間的協(xié)作需要通過(guò)通信完成怔檩,考慮到管道的緩存能力和安全性褪秀,我們選擇隊(duì)列作為通信內(nèi)容的載體。

multiprocessing模塊下實(shí)現(xiàn)封裝有很多基礎(chǔ)類型供給多線程間共享調(diào)用薛训,這足夠滿足我們的需要媒吗。

但是又一個(gè)問(wèn)題出現(xiàn)了。進(jìn)程的發(fā)送方可以根據(jù)需要向隊(duì)列中加入數(shù)據(jù)许蓖,但是對(duì)于接收方不斷地接收數(shù)據(jù)來(lái)保證加入隊(duì)列的數(shù)據(jù)可以得到及時(shí)地處理蝴猪。或許輪詢式的嘗試從隊(duì)列中獲取數(shù)據(jù)是個(gè)好選擇膊爪。

那么多久循環(huán)一次呢自阱?無(wú)限制循環(huán)卑雁?一個(gè)Linux tick時(shí)間系宜?無(wú)論多長(zhǎng),在空閑的時(shí)候都會(huì)造成對(duì)CPU的性能無(wú)意義損耗啃炸。所以另一個(gè)解決方案呼之欲出赃额,如果隊(duì)列為空那么等待一個(gè)信號(hào)加派,直到隊(duì)列中被放入數(shù)據(jù)后觸發(fā)這個(gè)信號(hào)后繼續(xù)該進(jìn)程。這個(gè)借助multiprocessing.Event()便可輕易做到跳芳。
那么怎么對(duì)Queue進(jìn)行封裝呢芍锦?關(guān)于這一點(diǎn)參考之前寫過(guò)的這篇文章: Python中輪詢觸發(fā)更替事件驅(qū)動(dòng)的簡(jiǎn)單方法
那么現(xiàn)在,我們已經(jīng)成功得對(duì)Queue進(jìn)行了封裝飞盆,那么我們是否可以對(duì)multiprocessing中manager里的其他的管理的數(shù)據(jù)內(nèi)容進(jìn)行封裝呢娄琉?于是我給出了如下的解決方案。

import multiprocessing

#這是所有操作符相關(guān)過(guò)或者其他功能相關(guān)的特殊函數(shù)吓歇。
common_list = {"__add__","__concat__","__contains__",
               "__truediv__","__floordiv__", "__and___",
               "__xor__","__invert__","__or__","__pow__",
               "__is__","__is_not__","__setitem__","__delitem__",
               "__getitem__","__lshift__","__mod__","__mul__",
               "__matmul__","__neg__","__not__","__pos__",
               "__rshift__","__setitem__","__delitem__","__getitem__",
               "__mod__","__sub__","__truth__","__lt__",
               "__le__","__eq__","__ne__","__ge__",
               "__gt__","__str__"}
#定義需要封裝事件信號(hào)的類型和觸發(fā)事件信號(hào)的方法
source_map = {
    'Queue': {'put'},
    'dict':{'__setitem__'}
}

# 封裝了multiprocessing.Manager孽水,
# 由于multiprocessing.Manager實(shí)際是一個(gè)方法,
# 所以使用了下述__getattribute__的方式城看。
class Manager(object):
    def __init__(self):
        self.manager = multiprocessing.Manager()

    # 將multiprocessing.Manager的方法映射向了Manager
    def __getattribute__(self, name):
        # 如果該方法在source_map 內(nèi)女气,則對(duì)該方法進(jìn)行封裝事件處理
        if name in source_map:
            # 初始化的方法,實(shí)例化被封裝的實(shí)例和該實(shí)例所用的事件信號(hào)
            def __init__(self_q, *args, **kwargs):
                self_q.sign = self.manager.Event()
                self_q.base = self.manager.__getattribute__(name)(*args, **kwargs)

            #生成一個(gè)對(duì)應(yīng)的函數(shù)的函數(shù)
            def functionfactory(i,m,self=None):
                if self:
                    def f(*args, **kwargs):
                        r = self.base.__getattribute__(m)(*args, **kwargs)
                        if i:
                            self.sign_set()
                        return r
                else:
                    def f(self_q, *args, **kwargs):
                        r = self_q.base.__getattribute__(m)(*args, **kwargs)
                        if i:
                            self_q.sign_set()
                        return r
                return f

            # 對(duì)一些屬性方法做映射
            def __getattribute__(self_q, name_q):
                if name_q[:5] == 'sign_':
                    return self_q.sign.__getattribute__(name_q[5:])
                elif name_q in source_map[name] and name_q not in common_list:
                    return functionfactory(True, name_q, self_q)
                elif name_q[:2]=='__' or name_q in ['sign', 'base'] or \
                    (name_q in common_list and name_q in source_map[name]):
                    return object.__getattribute__(self_q, name_q)
                else:
                    return self_q.base.__getattribute__(name_q)

            # __dir__ 方法的重寫
            def __dir__(self):
                r = (dir(self.base) 
                    + ["sign_%s" % m for m in dir(self.sign) if m[:2]!='__']
                    + ['sign', 'base'])
                r.sort()
                return r

            # 生成動(dòng)態(tài)生成類型的方法字典
            method_map = {
                      '__init__': __init__, 
                      '__getattribute__': __getattribute__,
                      '__dir__': __dir__
                  }
            
            for m in common_list.intersection(
                              dir(type(self.manager.__getattribute__(name)()))
                          ):
                method_map[m] = functionfactory(m in source_map[name],m)

            #生成并返回動(dòng)態(tài)類型
            return type(name, (object,), method_map)

        elif name in ['manager', 'source_map']:
            return object.__getattribute__(self, name)

        else:
            return self.manager.__getattribute__(self, name)

    def __dir__(self):
        r = dir(self.manager) + ['manager']
        r.sort()
        return r


if __name__ == "__main__":
    m = Manager()

    q = m.Queue()
    q.sign_set()
    print(q.sign_is_set())       # True
    q.sign_clear()
    q.put(1)
    print(q.sign_wait())         # True
    d = m.dict()
    d[3] = 2
    print(d.sign_is_set())       # True
    d.sign_clear()
    print(d[3])                  # 2
    print(d.sign_is_set())       # False
    print(d)                     # {3:2}

其中测柠,通過(guò)重寫__getattribute__方法的方式炼鞠,簡(jiǎn)單實(shí)現(xiàn)了對(duì)封裝的外部類和對(duì)應(yīng)內(nèi)部類的屬性進(jìn)行了映射缘滥。即當(dāng)在代碼中調(diào)用a.b的時(shí)候,其實(shí)是通過(guò)a.__getattribute__返回的b屬性簇搅。比如:

class AllMethodAllowed(object):
    def __getattribute__(self, name):
         if name in dir(object):
             return object.__getattribute__(self, name)
         else:
             return 'Hello, %s !' % name

if __name__=="__main__":
    ama = AllMethodAllowed()
    print(ama.Emma)                # Hello, Emma !
    print(ama.World)               # Hello, World !

但是python的基本操作是由實(shí)例直接對(duì)應(yīng)的內(nèi)置方法決定的而非__getattribute__方法獲取的完域,所以需要通過(guò)定義的方式進(jìn)行。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瘩将,一起剝皮案震驚了整個(gè)濱河市吟税,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌姿现,老刑警劉巖肠仪,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異备典,居然都是意外死亡异旧,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門提佣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)吮蛹,“玉大人,你說(shuō)我怎么就攤上這事拌屏〕闭耄” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵倚喂,是天一觀的道長(zhǎng)每篷。 經(jīng)常有香客問(wèn)我,道長(zhǎng)端圈,這世上最難降的妖魔是什么焦读? 我笑而不...
    開封第一講書人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮舱权,結(jié)果婚禮上矗晃,老公的妹妹穿的比我還像新娘。我一直安慰自己宴倍,他們只是感情好张症,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著啊楚,像睡著了一般吠冤。 火紅的嫁衣襯著肌膚如雪浑彰。 梳的紋絲不亂的頭發(fā)上恭理,一...
    開封第一講書人閱讀 51,258評(píng)論 1 300
  • 那天,我揣著相機(jī)與錄音郭变,去河邊找鬼颜价。 笑死涯保,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的周伦。 我是一名探鬼主播夕春,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼专挪!你這毒婦竟也來(lái)了及志?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤寨腔,失蹤者是張志新(化名)和其女友劉穎速侈,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體迫卢,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡倚搬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了乾蛤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片每界。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖家卖,靈堂內(nèi)的尸體忽然破棺而出眨层,到底是詐尸還是另有隱情,我是刑警寧澤篡九,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布谐岁,位于F島的核電站,受9級(jí)特大地震影響榛臼,放射性物質(zhì)發(fā)生泄漏伊佃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一沛善、第九天 我趴在偏房一處隱蔽的房頂上張望航揉。 院中可真熱鬧,春花似錦金刁、人聲如沸帅涂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)媳友。三九已至,卻和暖如春产捞,著一層夾襖步出監(jiān)牢的瞬間醇锚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留焊唬,地道東北人恋昼。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像赶促,于是被迫代替她去往敵國(guó)和親液肌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容