firefly(暗黑世界版v1.4)教程(三)工具类

辅助工具相关的文件都存放在utils文件内,也就是工具模块中
utils模块的文件结构
- 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的多线程迟滞回调模式运行的,要求软件返回的必须是一个同步对象,如果返回异步对象,则同样会导致软件异常,甚至崩溃
    # 所以在这里,你必须拥有足够的twisted使用知识,如果没有,请查阅相关文档

    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): # 根据服务名称注销服务
        """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): # 调用服务
        """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): # 用单线程方式调用服务
        """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): # 用多线程方式调用服务
        """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
    继承于服务类,主要用于指令服务(当客户端数据被解析成指令后可以直接根据指令内容调用服务)
    这里要求客户讲注册到本服务对象的服务名称写成 name_commandId
    比如:getUser_01,当我调用1号指令时,会自动解析成这个函数名称。 
    """
    def mapTarget(self, target):
        """Add a target to the service."""
        self._lock.acquire()
        try:
            key = int((target.__name__).split('_')[-1]) #分割函数么,并取第二段
            if key in self._targets: # 注册分割出来的函数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单例模式的元类
# 至于什么是单例模式,什么是元类,笔者就不做详细描述了
# 基本原则是,单例模式一般用于配置文件
# 单例模式的特点是在一个进程中,无论被实例化几次,都不会重新创建对象,而始终是第一个对象,这样既能保证配置文件在一个程序中的唯一性,类似于全局变量
# 这一块,如果无法理解也没有关系,可以直接跳过,你可以吧单例模式产生的类实例化的对象当成一个全局类,里面的变量当成全局变量。
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): # 指定创建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():
        """获取数据包的长度
        """
        pass
        
    def unpack():
        '''解包
        '''
        
    def pack():
        '''打包数据包
        '''
        
    
    


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  • 一:java概述:1,JDK:Java Development Kit,java的开发和运行环境,java的开发工...
    ZaneInTheSun阅读 2,635评论 0 11
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,093评论 1 32
  • 面向对象主要针对面向过程。 面向过程的基本单元是函数。 什么是对象:EVERYTHING IS OBJECT(万物...
    sinpi阅读 1,046评论 0 4
  • 小编费力收集:给你想要的面试集合 1.C++或Java中的异常处理机制的简单原理和应用。 当JAVA程序违反了JA...
    八爷君阅读 4,580评论 1 114
  • JAVA面试题 1、作用域public,private,protected,以及不写时的区别答:区别如下:作用域 ...
    JA尐白阅读 1,146评论 1 0