python firefly 游戏引擎 教程(三) 工具类

firefly辅助工具相关的文件都存放在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
  • 最后,我们再来看看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():
        '''打包数据包
        '''
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值