UML 类图

UML 类图 统一建模语言(英语:Unified Modeling Language,缩写 UML)是非专利的第三代建模和规约语言。UML是一种开放的方法,用于说明、可视化、构建和编写一个正在开发的、面向对象的、软件密集系统的制品的开放方法。UML展现了一系列最佳工程实践,这些最佳实践在对大规模,复杂系统进行建模方面,特别是在软件架构层次已经被验证有效。 以上是维基百科上对UML的定义,它定义了很多的图,本文主要介绍类图,是属于结构性图形中的静态图,本文所有图是通过OmniGraffle画的。 结构性图形(Structure diagrams)强调的是系统式的建模: 静态图(static diagram) 类图 对象图 包图 实现图(implementation diagram) 组件图 部署图 剖面图 复合结构图 行为式图形(Behavior diagrams)强调系统模型中触发的事件: 活动图 状态图 用例图 交互性图形(Interaction diagrams),属于行为图形的子集合,强调系统模型中的资料流程: 通信图 交互概述图(UML 2.0) 时序图(UML 2.0) 时间图(UML 2.0) 定义 UML类图是描述类的内部结构(属性, 方法等)和类与类之间的关系(泛化, 实现,组合, 聚合,关联,依赖),是一种静态结构图。是在面向对象程序设计中建模的常用方法,不仅是系统编码和测试的重要模型,以图的形式展示还可以简化人们对系统的理解。 格式 一般是用三层矩形框表示,第一层表示类的名称,第二层表示的是字段和属性,第三层则是类的方法,如果某一层没有则可以省略。第一层中,如果是抽象类,名称需用斜体显示。 属性和方法前面的符号(+、#、-等)代表可见性 Public(+) Protected(#) Private(-) Package(~) 第二层属性的格式是 可见性 名称 : 类型 [= 默认值] 第三层方法的格式是 可见性 名称(参数类型 参数, …) : 返回类型 类与类之间的关系 类图中类与类之间的关系主要由:继承、实现、依赖、关联、聚合、组合这六大类型。表示方式如下图: 泛化(generalization/extens) 泛化又称继承,是IS-A的关系,两个对象之间如果可以用IS-A来表示,就是继承关系:(..是..) 泛化关系用一条带空心箭头的实线表示;如下图表示(猫继承自动物)猫是(IS-A)动物 实现(realization/implements) 实现关系指的是一个class类实现interface接口(可以是多个)的功能,在Java中可以直接用关键字implements表示,在C++中目标类可用抽象类表示 实现关系用一条带空心箭头的虚线表示;如下图自行车必须实现车这个抽象类 注意这个车类是斜体代表抽象类 各种关系的强弱顺序: 泛化 = 实现 > 组合 > 聚合 > 关联 > 依赖...

July 9, 2020 · 1 min · 105 words · Fython

Flask项目中集成Celery

Flask项目中集成Celery Celery是一个简单高效的实时分布式任务队列系统,我们可以将一些耗时比较长或者计算密集的任务交给celery处理,它也支持定时任务类似于crontab。而web应用中可以将一些任务丢给celery异步处理,比如发邮件消息推送、模型推理等。简单的Flask应用集成Celery比简单,有官方文档可做参考,可较复杂的flask应用如使用了蓝图(blueprint)分了很多模块的怎么组织celery和各种任务就比较复杂官方也没有说明文档,一不小心就会陷入循环导入。下面就介绍一种celery集成方法。 官方文档demo中有一个make_celery的函数 def make_celery(app): celery = Celery( app.import_name, backend=app.config['CELERY_RESULT_BACKEND'], broker=app.config['CELERY_BROKER_URL'] ) celery.conf.update(app.config) class ContextTask(celery.Task): def __call__(self, *args, **kwargs): with app.app_context(): return self.run(*args, **kwargs) celery.Task = ContextTask return celery 这个函数主要用来创建Celery对象,并从flask上更新一些配置加入上下文环境,像文档上单文件是不会出问题的返回的celery对象直接在下面定义任务,然后集成到路由中。如果你flask app是使用app factories和蓝图(blueprint),那在这里定义的task又怎么在路由中引用呢,这就会导致循环引用问题。 我们可以把make_celery拆开来,首先创建celery对象然后等flask app初始化完成后在更新配置,这就解决问题了,任务单独放在tasks.py文件中也便于管理和查看 先来看最终项目结构图,就是flask web项目加入了celery flask-celery-demo ├── app │ ├── api │ │ ├── __init__.py │ │ └── views.py # 视图 │ ├── __init__.py │ └── tasks.py # celery任务 ├── config.py ├── requirements.txt ├── run.sh └── service.py # 应用入口 先解释下主要service....

May 24, 2020 · 2 min · 238 words · Fython

TCP连接和各状态浅析

TCP连接和各状态浅析 TCP协议中三次握手连接和四次挥手断开和其中的状态变化 TCP(Transmission Control Protocol)协议在OSI模型中属于传输层的协议(第4层)也是最常用的互联网协议,与UDP相比它是一种可靠的传输协议,建立和断开连接中一共有11种可能发生的状态(states)。 Linux系统中可以用ss -nat命令查看所有TCP连接情况如果是旧的系统没有此命令可以使用netstat代替只是输出格式不一致,统计当前所有TCP状态可以加管道实现 ss -nat | awk 'NR>1 { d[$1]++ } END { for (i in d) print i, d[i] }' 建立连接(三次握手) TCP是面向连接的所以传输双方在传输前要建立一条连接后才能通信,建立连接后TCP协议提供全双⼯(就是可以同时发送和接收不影响)的通信服务。建立连接的过程我们给它取了个生动的名字叫“三次握手”,因为从发起到建立连接一共有三个步骤也就是双方会发三个包,先看下面的图 首先客户端发送SYN(Synchronous)包到服务端告诉服务器开始建立连接,包里面会包含一个随机数(j)序列号(Sequence Number),此时客户端进入SYC-SENT状态。当然最初服务器是处于LISTEN状态监听某一个端口,本文图片以绿底黑框的都代表TCP状态。 服务端收到SYN发送应答SYN-ACK(Acknowledgement)携带确认号码(Acknowledge Number)为收到的序列号+1也就是j+1,加上一个自己的SYC序列号随机数(k),服务端把状态置为SYN-RECEIVED 客户端收到SYN-ACK包并发送确认号码k+1,此时客户端的状态为ESTABLISHED,服务器收到ACK后状态也变为ESTABLISHED 以下是wireshake抓包后TCP连接的三次握手,这里序列号码j和k都为0。 TCP A (port 65525) TCP B (port 443) LISTEN (Start) 1. SYN-SENT --> <SEQ=0><CTL=SYN> --> SYN-RECEIVE 2. ESTABLISHED <-- <SEQ=0><ACK=1><CTL=SYN,ACK> <-- SYN-RECEIVE 3. ESTABLISHED --> <SEQ=1><ACK=1><CTL=ACK> --< ESTABLISHED 断开连接(四次挥手) 断开连接称为“挥手”一共有四步每一方向占两步,由于TCP是全双工的所以关闭连接需要双方都完成关闭(close)才算结束,其中会涉及状态也就比握手多。客户端和服务端都可以发起挥手动作,先发送FIN包的动作叫主动关闭(active close)然后另一方回应ACK包叫执行被动关闭(passive colse),双方各完成一次主动和被动关闭一共四次。 客户端数据传输完毕发起断开连接(主动关闭),发送FIN包携带一个序列号(x)到服务端并更新自己的状态为FIN-WAIT-1 服务端收到FIN包返回ACK包(被动关闭),应答ACK确认序号为x+1,服务端此时的状态为CLOSE-WAIT。另一边客户端收到ACK更新状态为FIN-WAIT-2 服务端准备执行断开连接(主动关闭),此时服务端的状态还是CLOSE-WAIT,发送FIN包携带序列号(y)到客户端更新服务端状态为LAST-ACK,客户端收到FIN包后状态变为TIME-WAIT。 客户端收到FIN应答ACK(被动关闭)携带确认序号为y+1,服务端收到ACK立即关闭连接状态变为CLOSED 因为客户端最后不知道服务端有没有收到ACK包,所以默认等待两倍的MSL(Maximum Segment Lifetime),Linux上MSL一般为60s,等待120s使服务器如果没有收到ACK也能重传FIN包,最后把自己的状态置为CLOSED在此之前的MSL时间中一直是TIME-WAIT状态 看一个现实中的例子ssh连接退出...

February 13, 2020 · 1 min · 157 words · Fython

通过谷歌gRPC部署线上机器学习模型

通过谷歌gRPC部署线上机器学习模型 gRPC是谷歌开发的远程过程调用(RPC)系统,它使用HTTP/2通信,Protocol Buffer作为接口描述语言。分为服务端和客户端,跨平台不受语言限制。 本文主要在http服务中(以下代码使用的是flask),使用gPRC Python远程调用训练好的模型返回RESTful接口,机器学习模型是一个已训练好的人脸检测模型(mtcnn)作为演示。 所有源码托管在github,可按需要查看获取,下文只列出部分主要的代码提供一些思路。 Proto定义 使用gRPC必须先使用protocol buffers定义序列化的结构包括各对象、服务等所有类型,之后通过grpcio-tools生成服务端和客户端可用的代码,使用proto3格式。首先定义存放图片的Image用于请求参数,也就是入参是一张图片 // request image message Image { bytes raw_data = 1; int32 height = 2; int32 width = 3; string image_id = 4; MetaData _meta_data = 5; } message Image定义了单张图片的存放格式主要包括raw_data存放图片二进制,还有图片的长高和唯一id,_meta_data记录各种元数据具体实现可查看上面github源码infer.proto // each message Result message Result { Box box = 1; Landmarks landmarks = 2; double confidence = 3; } // return results message InferResults { string image_id = 1; MetaData _meta_data = 2; repeated Result results = 3; } message Result定义单张人脸格式每张人脸包括bounding box人脸框,landmarks5个点和置信度confidence,message InferResults定义了单张图上所有人脸和各种元数据。...

December 31, 2019 · 3 min · 517 words · Fython

Python描述符(descriptor)

Python 描述符(descriptor) Python 中有一个很少被使用或者用户自定义的特性,那就是描述符(descriptor),但它是@property, @classmethod, @staticmethod和super的底层实现机制,我今天就扒一扒它,官方文档对描述符的介绍如下 In general, a descriptor is an object attribute with “binding behavior”, one whose attribute access has been overridden by methods in the descriptor protocol: __get__(), __set__(), and __delete__(). If any of those methods are defined for an object, it is said to be a descriptor. 描述符是绑定了行为的对象属性(object attribute),实现了描述符协议(descriptor protocol),描述符协议就是定义了__get__(),__set__(),__delete__()中的一个或者多个方法,将描述符对象作为其他对象的属性进行访问时,就会产生一些特殊的效果。 上面的定义可能还是有些晦涩,一步步来 默认查找属性 在没有描述符定义情况下,我们访问属性的顺序如下,以a.x为例 查找实例字典里的属性就是a.__dict__['x']有就返回 往上查找父类的字典就是a.__class__.__dict__['x']有就返回 上面都没有就查找父类的基类(不包括元类(metaclass)) 如果定义了__getattr__就会返回此方法 最后都没有抛出AttributeError >>> class A: ... x = 8 ... ....

December 17, 2019 · 6 min · 1135 words · Fython