輔助工具相關(guān)的文件都存放在utils文件內(nèi)鳍置,也就是工具模塊中
utils模塊的文件結(jié)構(gòu)
- utils
- __init__.py
- interface.py # 接口類
- service.py # 服務類
- singleton.py # 單例模式
工具類在firefly中也非常重要,尤其是工具類中的服務器類(service.py)
該類幾乎貫穿整個分布式布局送淆,而分布式布局又是firefly的重中之重
下面我們首先就來看看服務類究竟都做了些什么
#coding:utf8
"""
Created on 2011-1-3
服務類
@author: sean_lan
"""
import threading
from twisted.internet import defer, threads
from twisted.python import log
class Service(object):
"""A remoting service
attributes:
============
* name - string, service name.
* runstyle
"""
# 在這里税产,我想作者應該是提供了兩種運行模式(我對這部分的理解,如有錯誤偷崩,請幫忙指出)
# 單線程模式 這種模式下運行的服務應該是一個 deffered 對象辟拷,也就是延遲服務,不能運行同步的耗時任務环凿,因為會堵塞整個服務線程梧兼,甚至導致軟件奔潰
# 多線程模式 在這種模式下放吩,服務是以twisted的多線程遲滯回調(diào)模式運行的智听,要求軟件返回的必須是一個同步對象,如果返回異步對象,則同樣會導致軟件異常到推,甚至崩潰
# 所以在這里考赛,你必須擁有足夠的twisted使用知識,如果沒有莉测,請查閱相關(guān)文檔
SINGLE_STYLE = 1 # 單線程運行
PARALLEL_STYLE = 2 # 多線程運行
def __init__(self, name, runstyle = SINGLE_STYLE):
self._name = name # 服務名稱
self._runstyle = runstyle #運行模式
self.unDisplay = set() # 類似黑名單
self._lock = threading.RLock() # 線程鎖
self._targets = {} #目標服務字典
# Keeps track of targets internally
def __iter__(self):
return self._targets.itervalues() # 返回所有服務
def addUnDisplayTarget(self,command):
"""Add a target unDisplay when client call it."""
self.unDisplay.add(command) # 將某個服務拉入黑名單
def mapTarget(self, target): # 注冊服務
"""Add a target to the service."""
self._lock.acquire()
try:
key = target.__name__
if key in self._targets:
exist_target = self._targets.get(key)
raise "target [%d] Already exists,\
Conflict between the %s and %s"%(key,exist_target.__name__,target.__name__)
self._targets[key] = target
finally:
self._lock.release()
def unMapTarget(self, target): # 注銷服務
"""Remove a target from the service."""
self._lock.acquire()
try:
key = target.__name__
if key in self._targets:
del self._targets[key]
finally:
self._lock.release()
def unMapTargetByKey(self,targetKey): # 根據(jù)服務名稱注銷服務
"""Remove a target from the service."""
self._lock.acquire()
try:
del self._targets[targetKey]
finally:
self._lock.release()
def getTarget(self, targetKey): #獲取服務
"""Get a target from the service by name."""
self._lock.acquire()
try:
target = self._targets.get(targetKey, None)
finally:
self._lock.release()
return target
def callTarget(self, targetKey,*args,**kw): # 調(diào)用服務
"""call Target
@param conn: client connection
@param targetKey: target ID
@param data: client data
"""
if self._runstyle == self.SINGLE_STYLE:
result = self.callTargetSingle(targetKey,*args,**kw)
else:
result = self.callTargetParallel(targetKey,*args,**kw)
return result
def callTargetSingle(self,targetKey,*args,**kw): # 用單線程方式調(diào)用服務
"""call Target by Single
@param conn: client connection
@param targetKey: target ID
@param data: client data
"""
target = self.getTarget(targetKey)
self._lock.acquire()
try:
if not target:
log.err('the command '+str(targetKey)+' not Found on service')
return None
if targetKey not in self.unDisplay:
log.msg("call method %s on service[single]"%target.__name__)
defer_data = target(*args,**kw)
if not defer_data:
return None
if isinstance(defer_data,defer.Deferred):
return defer_data
d = defer.Deferred()
d.callback(defer_data)
finally:
self._lock.release()
return d
def callTargetParallel(self,targetKey,*args,**kw): # 用多線程方式調(diào)用服務
"""call Target by Single
@param conn: client connection
@param targetKey: target ID
@param data: client data
"""
self._lock.acquire()
try:
target = self.getTarget(targetKey)
if not target:
log.err('the command '+str(targetKey)+' not Found on service')
return None
log.msg("call method %s on service[parallel]"%target.__name__)
d = threads.deferToThread(target,*args,**kw)
finally:
self._lock.release()
return d
class CommandService(Service):
"""A remoting service
繼承于服務類颜骤,主要用于指令服務(當客戶端數(shù)據(jù)被解析成指令后可以直接根據(jù)指令內(nèi)容調(diào)用服務)
這里要求客戶講注冊到本服務對象的服務名稱寫成 name_commandId
比如:getUser_01,當我調(diào)用1號指令時忍抽,會自動解析成這個函數(shù)名稱董朝。
"""
def mapTarget(self, target):
"""Add a target to the service."""
self._lock.acquire()
try:
key = int((target.__name__).split('_')[-1]) #分割函數(shù)么鸠项,并取第二段
if key in self._targets: # 注冊分割出來的函數(shù)ID
exist_target = self._targets.get(key)
raise "target [%d] Already exists,\
Conflict between the %s and %s"%(key,exist_target.__name__,target.__name__)
self._targets[key] = target
finally:
self._lock.release()
def unMapTarget(self, target):
"""Remove a target from the service."""
self._lock.acquire()
try:
key = int((target.__name__).split('_')[-1])
if key in self._targets:
del self._targets[key]
finally:
self._lock.release()
第二步,我們看一下單例模式(singleton.py)
# 這個文件提供了python單例模式的元類
# 至于什么是單例模式子姜,什么是元類帅刊,筆者就不做詳細描述了
# 基本原則是纪蜒,單例模式一般用于配置文件
# 單例模式的特點是在一個進程中,無論被實例化幾次,都不會重新創(chuàng)建對象境蔼,而始終是第一個對象,這樣既能保證配置文件在一個程序中的唯一性畦徘,類似于全局變量
# 這一塊鸽捻,如果無法理解也沒有關(guān)系呼巴,可以直接跳過,你可以吧單例模式產(chǎn)生的類實例化的對象當成一個全局類御蒲,里面的變量當成全局變量衣赶。
class Singleton(type):
"""Singleton Metaclass"""
def __init__(self, name, bases, dic):
super(Singleton, self).__init__(name, bases, dic)
self.instance = None
def __call__(self, *args, **kwargs):
if self.instance is None:
self.instance = super(Singleton, self).__call__(*args, **kwargs)
return self.instance
class test(metaclass=Singleton): # 指定創(chuàng)建Foo的type為SingletonType
def __init__(self):
self.json_config = None
#
# print(test().json_config)
# test().json_config = {"a":1}
# print(test().json_config)
# print(test())
# print(test())
最后,我們再來看看interface.py文件
# 這個作為一個接口類碘箍,以該類為接口的類必須要完成該類所提供的方法遵馆,否則會報錯
'''
Created on 2013-10-17
@author: lan (www.9miao.com)
'''
from __future__ import division, absolute_import
from zope.interface import Interface
class IDataPackProtoc(Interface):
def getHeadlength():
"""獲取數(shù)據(jù)包的長度
"""
pass
def unpack():
'''解包
'''
def pack():
'''打包數(shù)據(jù)包
'''