-
零件加工一致性评价技术
2019-12-27 18:48:16零件加工一致性评价技术,宋忠伟,陶桂宝,本文针对我国机床加工精度保持性差、可靠性不高等问题,提出了加工相对一致性和绝对一致性的相关概念。首先从几何精度(包括尺寸 -
图像评价的基本指标和概念
2020-08-13 09:12:035.失真-均匀性-一致性交互-瑕疵检测 6.SFR–查找最清晰的文件–Batchview–MTF比较–OIS/图像比较–倾斜边缘算法–锐度/SQF 7.分辨率测试:SFR——星图——对数频率——对数F——对比度——随机(溢出硬币等)——...1.图像质量概念:清晰度(sharpness)、锐化(sharpening)、噪声-原始转换
清晰度(sharpness)在边缘等特征上最为明显。它可以通过边缘(阶跃)响应来测量。
成像系统的每个组件都会影响整个系统的响应(通常会降低清晰度)
注:图像分析可以分为空间域与频域。通过在频域中描述成像系统的性能,可以更容易地描述和可视化成像系统的性能。复合信号(音频或图像)可以通过组合由正弦波组成的信号(以周期或频率为特征)来创建。高频对应于精细的细节。系统在高频(短周期)下的响应越好,系统可以传达的细节就越多。
SFR (Spatial Frequency Response) 空间频率响应和MTF (Modulation Transfer Function) 调制传递函数是测量清晰度(sharpness)的关键。
清晰度(sharpness)总结:
•清晰度在边缘等特征上最为明显,它是重要的。但在细纹理(树叶,皮肤等)不太明显
•清晰度可从以下几种图案中测量,对于线性系统,所有的结果都是相似的。
•许多成像系统都是高度非线性的(处理随图像内容而变化;边缘的行为与纹理不同),因此通常需要多张图表来表征一个系统。
•具有1/f频谱(*)的图表具有标度不变性,这使得测量非常方便:如果图表频谱和比例已知,则MTF计算非常简单。锐化(hsarpening)影响MTF测量–提高图像清晰度;大多数数码相机的图像看起来柔和而不锐化。所有的数字图像都能从锐化中受益,但过多的锐化会降低图像的质量;Raw格式图像没有锐化,但锐化应用于几乎所有的数字图像-在相机,Raw转换,或图像编辑器。锐化的操作就是从每个像素中减去一小部分相邻像素,使产生的信号更加清晰,提高高空间频率下的对比度(也提高MTF50),数量取决于锐化分数和半径。锐化传递函数:
由于锐化对MTF有很强的影响,因此需要一个基于锐化的度量(过锐化、过冲等)来充分表征MTF响应。反锐化掩模(USM)是一种替代算法:从原始边缘的高斯模糊副本中减去一小部分。过度锐化会增加可见噪声,当MTF和信噪比(SNR)的频率被强烈增强时,会降低外观。
噪声(noise):•信号电平的随机扰动。•薄膜严重退化。•以RMS(均方根)电压测量,与标准偏差σ相同。•噪声具有频谱。•噪声在平滑区域(如天空)最为明显,通常采用降噪(NR=低通滤波,即高频衰减;与锐化正好相反)。•低通滤波模糊边缘。•为了在保持边缘质量的同时降低噪声,经常采用非线性、非均匀的双边滤波器。图像处理在不同的位置是不同的!锐化(高频增强)是最强的边缘附近,而噪音降低(高频切割)是最强的远离边缘。
2.图像质量因子
- 锐度
- 横向色差
- 噪声
- 颜色精度
- 色调响应与对比
- 动态范围
- 曝光精度
- 光衰减
- 透镜畸变
- 感光度
-
论文研究-考虑指标均衡度影响和专家人数不一致因素的信息系统综合评价模型.pdf
2019-09-20 10:35:03提出一个用于信息系统综合评价的数学模型,该模型能够适应对各评价对象进行评价的专家数目不一致,或参与评价某对象各指标的专家数目不一致的情况;同时,模型中引入了... -
补偏救弊 | 关于一致性读与语句性能关系的一大误区
2018-02-28 00:00:00个人网站 www.HelloDBA.com研究背景实际上,我们所说的保证同一时间点一致性读的概念,其背后是物理层面的 block 读,Oracle 会依据你发出 select 命令,记录下那一刻的 SCN 值,然后以这个 SCN 值去同所读的每个 ...作者简介
黄玮(Fuyuncat)
资深 Oracle DBA,致力于数据库底层技术的研究,其作品获得广大同行的高度评价。
个人网站 www.HelloDBA.com
研究背景
实际上,我们所说的保证同一时间点一致性读的概念,其背后是物理层面的 block 读,Oracle 会依据你发出 select 命令,记录下那一刻的 SCN 值,然后以这个 SCN 值去同所读的每个 block 上的 SCN 比较,如果读到的块上的 SCN 大于 select 发出时记录的 SCN,则需要利用 Undo 得到该 block 的前镜像,在内存中构造 CR 块(Consistent Read)。
一致性读(Consistent Gets,CG)是反映 SQL 语句性能的一项重要数据。它通常作为我们语句调优的指标。一般情况下,通过该数据可以比较两条语句或者同一语句的不同执行计划之间的性能。然而,某些情况下,它并不会完全反映出语句的性能。
分析探讨
我们先看两份性能统计数据:
SQL代码
SQL 1:
Statistics
-----------------------
0 recursive calls
0 db block gets
460 consistent gets
0 physical reads
0 redo size
1203583 bytes sent via SQL*Net to client
3868 bytes received via SQL*Net from client
306 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4563 rows processed
SQL 2:
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
167 consistent gets
0 physical reads
0 redo size
267325 bytes sent via SQL*Net to client
3868 bytes received via SQL*Net from client
306 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
4563 rows processed
可以看到,第一条语句的 CG 是第二条语句的近3倍,看起来应该是第二条语句的性能更好。是否真是如此?
那再看看这两条语句是如何构造执行的:
SQL代码
HelloDBA.COM> create table t1 as select * from dba_tables;
Table created.
HelloDBA.COM> create table t2 as select * from dba_users;
Table created.
HelloDBA.COM> exec dbms_stats.gather_table_stats('DEMO', 'T1');
PL/SQL procedure successfully completed.
HelloDBA.COM> exec dbms_stats.gather_table_stats('DEMO', 'T2');
PL/SQL procedure successfully completed.
HelloDBA.COM> set timing on
HelloDBA.COM> set autot trace
HelloDBA.COM> select * from t1;
4563 rows selected.
Elapsed: 00:00:00.10
Execution Plan
----------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4563 | 1078K| 49 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| T1 | 4563 | 1078K| 49 (0)| 00:00:01 |
--------------------------------------------------------------------------
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
460 consistent gets
0 physical reads
0 redo size
1203583 bytes sent via SQL*Net to client
3868 bytes received via SQL*Net from client
306 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4563 rows processed
HelloDBA.COM> select * from t1, t2 where t2.username='SYS';
4563 rows selected.
Elapsed: 00:00:00.23
Execution Plan
----------------------------------------------------------
Plan hash value: 1323614827
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4563 | 1581K| 52 (0)| 00:00:01 |
| 1 | MERGE JOIN CARTESIAN| | 4563 | 1581K| 52 (0)| 00:00:01 |
|* 2 | TABLE ACCESS FULL | T2 | 1 | 113 | 3 (0)| 00:00:01 |
| 3 | BUFFER SORT | | 4563 | 1078K| 49 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL | T1 | 4563 | 1078K| 49 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("T2"."USERNAME"='SYS')
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
167 consistent gets
0 physical reads
0 redo size
267325 bytes sent via SQL*Net to client
3868 bytes received via SQL*Net from client
306 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
4563 rows processed
这两条语句并不复杂。如果我们忽略性能统计数据,我们很容易就从其语句逻辑结构或者执行计划判断出它们的性能谁优谁劣。
但是为什么第二条语句的 CG 更少呢?
我们对它们作 SQL 运行跟踪,再看格式化的跟踪结果:
SQL代码
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
4563 4563 4563 MERGE JOIN CARTESIAN (cr=167 pr=0 pw=0 time=38433 us cost=52 size=1619865 card=4563)
1 1 1 TABLE ACCESS FULL T2 (cr=3 pr=0 pw=0 time=78 us cost=3 size=113 card=1)
4563 4563 4563 BUFFER SORT (cr=164 pr=0 pw=0 time=22958 us cost=49 size=1104246 card=4563)
4563 4563 4563 TABLE ACCESS FULL T1 (cr=164 pr=0 pw=0 time=11815 us cost=49 size=1104246 card=4563)
这是第二条语句的计划统计数据。显然,它包含两个部分:对 T1 和 T2 的全表扫描访问。
在该执行计划当中,T1 的全表扫描的 CG 为 164,当时为什么在第一条语句中对其的全部扫描产生的 CG 为 466 呢?这是因为数据获取数组大小(fetch array size)设置的影响。
如下,在 SQLPlus 当中,该设置默认值为15,如果我们将其设得足够大,CG 将变为165,没错。因为无论该数组大小设为多大,Oracle 总是在第一次读取时读取第一条记录。
SQL代码
HelloDBA.COM> set arraysize 5000
HelloDBA.COM> set autot trace stat
HelloDBA.COM> select * from t1;
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
165 consistent gets
0 physical reads
0 redo size
1147039 bytes sent via SQL*Net to client
524 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4563 rows processed
关于全部扫描的 CG 可以参考该文章了解更多细节:http://www.hellodba.com/reader.php?ID=39&lang=EN
F2 是一张小表,它的全表扫描访问产生的CG为3。
写到这是否可以结束了呢?现在将第二条语句的过滤条件移除看看。
SQL代码
HelloDBA.COM> select * from t1, t2;
246402 rows selected.
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
219 consistent gets
0 physical reads
0 redo size
14113903 bytes sent via SQL*Net to client
181209 bytes received via SQL*Net from client
16428 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
246402 rows processed
仅仅 219 CG?这是一个笛卡尔乘积的关联(无关联条件),怎么会是如此少的 CG 呢?
再次产生 SQL 跟踪文件:
SQL代码
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
246402 246402 246402 MERGE JOIN CARTESIAN (cr=219 pr=0 pw=0 time=957833 us cost=2553 size=87472710 card=246402)
54 54 54 TABLE ACCESS FULL T2 (cr=55 pr=0 pw=0 time=728 us cost=3 size=6102 card=54)
246402 246402 246402 BUFFER SORT (cr=164 pr=0 pw=0 time=433549 us cost=2550 size=1104246 card=4563)
4563 4563 4563 TABLE ACCESS FULL T1 (cr=164 pr=0 pw=0 time=10674 us cost=47 size=1104246 card=4563)
T1 的全表扫描的 CG 并未变化,T2 的 CG 增加为 55。55 意味着什么?它是 T2 的数据记录数加一。
SQL代码
HelloDBA.COM> select count(*) from t2;
COUNT(*)
----------
54
但是,笛卡尔乘积不是意味着 m×n 吗?为什么结果是 m+n?
实际上,Oracle 确实对 T1 做了多次重复访问。不过,第一次访问后,读取到的数据被缓存到了私有工作区,接下来的访问就是从私有内存而非共享内存中读取数据。因此,这些访问就没有被记入 CG 当中。
为了获取实际的访问次数,我们使用嵌套关联提示使其从共享内存中读取数据:
SQL代码
HelloDBA.COM> select /*+use_nl(t1) leading(t1)*/* from t1, t2;
246402 rows selected.
Elapsed: 00:00:07.43
Execution Plan
----------------------------------------------------------
Plan hash value: 787647388
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 246K| 83M| 5006 (1)| 00:01:01 |
| 1 | MERGE JOIN CARTESIAN| | 246K| 83M| 5006 (1)| 00:01:01 |
| 2 | TABLE ACCESS FULL | T1 | 4563 | 1078K| 49 (0)| 00:00:01 |
| 3 | BUFFER SORT | | 54 | 6102 | 4956 (1)| 00:01:00 |
| 4 | TABLE ACCESS FULL | T2 | 54 | 6102 | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
4568 consistent gets
0 physical reads
0 redo size
16632868 bytes sent via SQL*Net to client
181209 bytes received via SQL*Net from client
16428 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
246402 rows processed
尽管执行计划没有变化,但是 CG 的变化却相当明显。
研究收获
从这个例子中可以注意到两点:
1. 数据获取数组大小会影响 CG;
2. CG 仅包含从共享内存读取的次数;
注:
测试环境为: Oracle 11.2.0.3 on Oracle Linux 5 64bit
资源下载
关注公众号:数据和云(OraNews)回复关键字获取
‘2017DTC’,2017 DTC 大会 PPT
‘DBALIFE’,“DBA 的一天”海报
‘DBA04’,DBA 手记4 经典篇章电子书
‘RACV1’, RAC 系列课程视频及 PPT
‘122ARCH’,Oracle 12.2 体系结构图
‘2017OOW’,Oracle OpenWorld 资料
‘PRELECTION’,大讲堂讲师课程资料
-
一致性哈希原理与应用
2018-06-15 11:28:24概念百科释义一致性哈希算法简单来说就是一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似。一致性哈希修正了CARP使用的简 单哈希算法带来的问题,使得分布式...概念
百科释义
一致性哈希算法简单来说就是一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似。一致性哈希修正了CARP使用的简 单哈希算法带来的问题,使得分布式哈希(DHT)可以在P2P环境中真正得到应用。
哈希算法评价标准
在动态的缓存环境中,有下面这么几条标准,可以用来判断一个哈希算法的好坏。借用网上 一篇文章 对此的描述。
平衡性(Balance)
:平衡性是指哈希的结果能够尽可能分布到所有的缓冲中去,这样可以使得所有的缓冲空间都得到利用。很多哈希算法都能够满足这一条件。单调性(Monotonicity)
:单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中,又有新的缓冲加入到系统中。哈希的结果应能够保证原有已分配的内容可以被映射到原有的或者新的缓冲中去,而不会被映射到旧的缓冲集合中的其他缓冲区。分散性(Spread)
:在分布式环境中,终端有可能看不到所有的缓冲,而是只能看到其中的一部分。当终端希望通过哈希过程将内容映射到缓冲上时,由于不同终端所见的缓冲范围有可能不同,从而导致哈希的结果不一致,最终的结果是相同的内容被不同的终端映射到不同的缓冲区中。这种情况显然是应该避免的,因为它导致相同内容被存储到不同缓冲中去,降低了系统存储的效率。分散性的定义就是上述情况发生的严重程度。好的哈希算法应能够尽量避免不一致的情况发生,也就是尽量降低分散性。负载(Load)
:负载问题实际上是从另一个角度看待分散性问题。既然不同的终端可能将相同的内容映射到不同的缓冲区中,那么对于一个特定的缓冲区而言,也可能被不同的用户映射为不同 的内容。与分散性一样,这种情况也是应当避免的,因此好的哈希算法应能够尽量降低缓冲的负荷。
通用代码
在正式解释一致性哈希算法之前,先贴一下待会要用到的通用的代码。
constrants.py
#coding: utf8 servers = [ "192.168.0.1:11211", "192.168.0.2:11211", "192.168.0.3:11211", "192.168.0.4:11211", ] entries = [ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", ]
func.py
#coding: utf8 from hashlib import md5 def hashcode(key=""): if key == None or key == "": return 0 return int(md5(str(key).encode('utf8')).hexdigest(), 16) def print_pretty_list(ls=[]): for item in ls: print(item) def print_pretty_dict(dc={}): for key, value in dc.items(): print(f'{key}: {value}') def compute_cache_percentage(oldcache, newcache): result = {key: 0 for key in oldcache.keys()} for key, value in oldcache.items(): if key in newcache.keys(): result[key] = len(list(set(value).intersection(set(newcache[key])))) return result def get_map_list_key(maplist): result = [] for map in maplist: result.extend(map.keys()) return result def compute_cache_percentage_ring(oldcache, newcache): result = {key: 0 for key in oldcache.keys()} # 这里每一个value其实都是一个装了字典map的列表 for node, maplist in oldcache.items(): if node in newcache.keys(): oldkeys = get_map_list_key(maplist) newkeys = get_map_list_key(newcache[node]) result[node] = len(list(set(oldkeys).intersection(set(newkeys)))) return result def compute_cache_percentage_virtual_ring(oldcache, newcache): result = {key.split("#")[0]: 0 for key in oldcache.keys()} # 这里每一个value其实都是一个装了字典map的列表 for node, maplist in oldcache.items(): if node in newcache.keys(): oldkeys = get_map_list_key(maplist) newkeys = get_map_list_key(newcache[node]) temp = str(node).split("#")[0] result[temp] += len(list(set(oldkeys).intersection(set(newkeys)))) return result
硬哈希
硬哈希,一般又被称为普通哈希。其原理较为简单,当然实现方式也多种多样。比如
取余数法
等。单调性也能很好的满足。硬哈希在缓存服务的适用场景一般是缓存环境不怎么发生变化,对于缓存服务器群的稳定性要求较高。一旦服务器群出现故障,就有可能导致井喷现象,出现缓存服务瞬间崩溃。这么说可能不太容易理解,下面举个通俗点的例子。
张大胖负责维护公司的缓存服务群,手里现在有10台机器,每台服务器的内存使用率都达到了95%, 而且老板还贼抠,就是不给配新机器。这天,实习生小李写了个日志分析的脚本,没有考虑到目前服务器内存已然吃紧的现状,就直接执行了。结果第三台服务器出现了严重的
Out Of Memory
问题,导致服务器直接死掉了。然后缓存数据直接全部丢失。这个时候原本的10台服务器,变成了9台。原本可以命中的缓存内容这下都失效了。导致了缓存服务被迫更新,瞬间服务器压力都上来了。不仅缓存服务器挂了,后台的MySQL服务器也撑不住这么大规模的请求啊,公司的整个业务线都陷入了瘫痪的状态。简易实现硬哈希 hard-hash.py
# coding: utf8 from hashlib import * from constraints import servers, entries from func import * length = len(servers) details1 = {key:[] for key in servers} for entry in entries: # keyhash = sum([ord(c) for c in entry]) keyhash = hashcode(entry) server = servers[keyhash%length] details1[server].append(entry) print_pretty_dict(details1) print("---"*28) del servers[0] length = len(servers) details2 = {key:[] for key in servers} for entry in entries: # keyhash = sum([ord(c) for c in entry]) keyhash = hashcode(entry) server = servers[keyhash%length] details2[server].append(entry) print_pretty_dict(details2) print("---"*28) servers.insert(0, "192.168.0.1:11211") servers.append("192.168.0.5:11211") length = len(servers) details3 = {key:[] for key in servers} for entry in entries: # keyhash = sum([ord(c) for c in entry]) keyhash = hashcode(entry) server = servers[keyhash%length] details3[server].append(entry) print_pretty_dict(details3) # -------计算缓存度 print("==="*7) print_pretty_dict(compute_cache_percentage(details1, details2)) print("---"*20) print_pretty_dict(compute_cache_percentage(details1, details3))
硬哈希缓存效果
python hard-hash.py 192.168.0.1:11211: ['o', 's', 'u', 'w'] 192.168.0.2:11211: ['a', 'd', 'g', 'h', 'i', 'j', 'n', 'q', 'r', 'y'] 192.168.0.3:11211: ['e', 'p', 't', 'v', 'x'] 192.168.0.4:11211: ['b', 'c', 'f', 'k', 'l', 'm', 'z'] ------------------------------------------------------------------------------------ 192.168.0.2:11211: ['d', 'k', 'l', 'm', 's', 't', 'v', 'x'] 192.168.0.3:11211: ['a', 'b', 'c', 'e', 'h', 'i', 'n', 'o', 'p', 'r', 'u', 'w', 'y'] 192.168.0.4:11211: ['f', 'g', 'j', 'q', 'z'] ------------------------------------------------------------------------------------ 192.168.0.1:11211: ['j', 'n', 't'] 192.168.0.2:11211: ['e', 'm', 'p', 'q', 'w'] 192.168.0.3:11211: ['a', 'i', 'l'] 192.168.0.4:11211: ['b', 'c', 'd', 'g', 'h', 'k', 'o', 's', 'v', 'x', 'z'] 192.168.0.5:11211: ['f', 'r', 'u', 'y'] ===================== 192.168.0.1:11211: 0 192.168.0.2:11211: 1 192.168.0.3:11211: 2 192.168.0.4:11211: 2 ------------------------------------------------------------ 192.168.0.1:11211: 0 192.168.0.2:11211: 1 192.168.0.3:11211: 0 192.168.0.4:11211: 4
可以看出,动态缓存环境下,硬哈希的命中率并不高。
一致哈希
一致性哈希算法的基本实现原理是将机器节点和key值都按照一样的hash算法映射到一个0~2^32(也不一定非得是2^32, 理论上能让节点分布均匀的‘环’就够了)的圆环上。当有一个写入缓存的请求到来时,计算Key值k对应的哈希值Hash(k),如果该值正好对应之前某个机器节点的Hash值,则直接写入该机器节点,如果没有对应的机器节点,则顺时针查找下一个节点,进行写入,如果超过2^32还没找到对应节点,则从0开始查找(因为是环状结构)。比如下面盗的一张图。
简易代码实现consisthash.py
# coding: utf8 # 简单一致性hash实现 from constraints import servers, entries from func import print_pretty_dict, hashcode, compute_cache_percentage, compute_cache_percentage_ring class ConsistHash(object): """ 简单一致性哈希算法实现 """ def __init__(self, servers=[]): self.servers = servers # sorted list which contains server nodes. self.ring = [] # node:[hashcode1, hashcode2, ...] self.hashnodemap = {} for server in self.servers: self.addNode(server) def addNode(self, node): code = hashcode(node) self.hashnodemap[code] = node self.ring.append(code) self.ring.sort() def removeNode(self, node): del self.hashnodemap[hashcode(node)] self.ring.remove(hashcode(node)) def getNode(self, key): code = hashcode(key) for ringitem in self.ring[::-1]: if ringitem <= code: return self.hashnodemap[ringitem] return self.hashnodemap[self.ring[0]] class Cacher(object): """ 普通一致性哈希算法的应用 """ def __init__(self, servers): self.c = ConsistHash(servers=servers) self.container = {key:[] for key in servers} def addServer(self, server): self.c.addNode(server) self.container[server] = [] def removeServer(self, server): self.c.removeNode(server) del self.container[server] def cache(self, key, value): server = self.c.getNode(key) self.container[server].append({key: value}) def get(self, key): server = self.c.getNode(key) return self.container[server].items()[key] if __name__ == "__main__": # c = ConsistHash(servers=servers) # print_pretty_list(c.ring) # print_pretty_dict(c.hashnodemap) cacher1 = Cacher(servers) for entry in entries: cacher1.cache(entry, entry) print_pretty_dict(cacher1.container) # 删除一个服务器 cacher3 = Cacher(servers) cacher3.removeServer("192.168.0.1:11211") for entry in entries: cacher3.cache(entry, entry) print_pretty_dict(cacher3.container) # 添加一个服务器 cacher2 = Cacher(servers) cacher2.addServer("192.168.0.5:11211") for entry in entries: cacher2.cache(entry, entry) print_pretty_dict(cacher2.container) # 计算缓存有效度 print_pretty_dict(compute_cache_percentage_ring(cacher1.container, cacher2.container)) print_pretty_dict(compute_cache_percentage_ring(cacher1.container, cacher3.container))
缓存效果
python consisthash.py 192.168.0.1:11211: [{'a': 'a'}, {'c': 'c'}, {'h': 'h'}, {'j': 'j'}, {'l': 'l'}, {'r': 'r'}, {'s': 's'}, {'y': 'y'}] 192.168.0.2:11211: [{'b': 'b'}, {'d': 'd'}, {'f': 'f'}, {'g': 'g'}, {'i': 'i'}, {'k': 'k'}, {'m': 'm'}, {'n': 'n'}, {'p': 'p'}, {'q': 'q'}, {'u': 'u'}, {'v': 'v'}, {'x': 'x'}] 192.168.0.3:11211: [] 192.168.0.4:11211: [{'e': 'e'}, {'o': 'o'}, {'t': 't'}, {'w': 'w'}, {'z': 'z'}] 192.168.0.2:11211: [{'a': 'a'}, {'b': 'b'}, {'c': 'c'}, {'d': 'd'}, {'f': 'f'}, {'g': 'g'}, {'h': 'h'}, {'i': 'i'}, {'j': 'j'}, {'k': 'k'}, {'l': 'l'}, {'m': 'm'}, {'n': 'n'}, {'p': 'p'}, {'q': 'q'}, {'r': 'r'}, {'s': 's'}, {'u': 'u'}, {'v': 'v'}, {'x': 'x'}, {'y': 'y'}] 192.168.0.3:11211: [] 192.168.0.4:11211: [{'e': 'e'}, {'o': 'o'}, {'t': 't'}, {'w': 'w'}, {'z': 'z'}] 192.168.0.1:11211: [] 192.168.0.2:11211: [{'b': 'b'}, {'d': 'd'}, {'f': 'f'}, {'g': 'g'}, {'i': 'i'}, {'k': 'k'}, {'m': 'm'}, {'n': 'n'}, {'p': 'p'}, {'q': 'q'}, {'u': 'u'}, {'v': 'v'}, {'x': 'x'}] 192.168.0.3:11211: [] 192.168.0.4:11211: [{'e': 'e'}, {'o': 'o'}, {'t': 't'}, {'w': 'w'}, {'z': 'z'}] 192.168.0.5:11211: [{'a': 'a'}, {'c': 'c'}, {'h': 'h'}, {'j': 'j'}, {'l': 'l'}, {'r': 'r'}, {'s': 's'}, {'y': 'y'}] 192.168.0.1:11211: 0 192.168.0.2:11211: 13 192.168.0.3:11211: 0 192.168.0.4:11211: 5 192.168.0.1:11211: 0 192.168.0.2:11211: 13 192.168.0.3:11211: 0 192.168.0.4:11211: 5
结果表明: 与硬哈希缓存命中率相比,一致哈希的缓存命中率确实提高了不少。
“虚拟”一致哈希
虽然缓存命中率得到了提高,但是仅仅这样还不能够真正的应用到实际生产环境中,因为目前的一致哈希还缺少了平衡性。
在此基础上,算法大佬们又引入了
虚拟节点
的概念。“虚拟节点”( virtual node )是实际节点(机器)在 hash 空间的复制品( replica ),一实际个节点(机器)对应了若干个“虚拟节点”,这个对应个数也成为“复制个数”,“虚拟节点”在 hash 空间中以hash值排列
带有虚拟节点的一致哈希virtualconstisthash.py
# coding: utf8 # 带有虚拟节点的一致性哈希算法实现 from constraints import servers, entries from func import print_pretty_dict, hashcode, print_pretty_list from func import compute_cache_percentage from func import compute_cache_percentage_ring from func import compute_cache_percentage_virtual_ring class VirtualConsistHash(object): """ 带有虚拟节点的一致性哈希算法实现 """ def __init__(self, servers=[], replicas=3): self.servers = servers # sorted list which contains server nodes. self.ring = [] # node:[hashcode1, hashcode2, ...] # 虚拟节点的个数,其实这个名字叫虚拟节点的个数不太合适,每个真实节点“虚拟化”后的节点个数比较好 self.replicas = replicas self.hashnodemap = dict() for server in self.servers: self.addNode(server) def addNode(self, node): for i in range(0, self.replicas): temp = "{}#{}".format(node, i) code = hashcode(temp) self.hashnodemap[code] = temp self.ring.append(code) self.ring.sort() def removeNode(self, node): for i in range(0, self.replicas): temp = "{}#{}".format(node, i) code = hashcode(temp) self.ring.remove(code) del self.hashnodemap[code] def getNode(self, key): code = hashcode(key) for ringitem in self.ring[::-1]: if ringitem <= code: return self.hashnodemap[ringitem] return self.hashnodemap[self.ring[0]] class Cacher(object): """ 带有虚拟节点的一致性哈希算法的应用 """ def __init__(self, servers): self.c = VirtualConsistHash(servers=servers) self.container = {"{}#{}".format(server, index): [] for index in range(0, self.c.replicas) for server in self.c.servers} def addServer(self, server): self.c.addNode(server) for i in range(0, self.c.replicas): temp = "{}#{}".format(server, i) self.container[temp] = [] def removeServer(self, server): self.c.removeNode(server) for i in range(0, self.c.replicas): temp = "{}#{}".format(server, i) del self.container[temp] def cache(self, key, value): server = self.c.getNode(key) self.container[server].append({key: value}) def get(self, key): server = self.c.getNode(key) return self.container[server].items()[key] if __name__ == "__main__": c = VirtualConsistHash(servers=servers) print_pretty_list(c.ring) print_pretty_dict(c.hashnodemap) cacher1 = Cacher(servers) for entry in entries: cacher1.cache(entry, entry) print_pretty_dict(cacher1.container) # 删除一个服务器 cacher3 = Cacher(servers) cacher3.removeServer("192.168.0.1:11211") for entry in entries: cacher3.cache(entry, entry) print_pretty_dict(cacher3.container) # 添加一个服务器 cacher2 = Cacher(servers) cacher2.addServer("192.168.0.5:11211") for entry in entries: cacher2.cache(entry, entry) print_pretty_dict(cacher2.container) # 计算缓存有效度 print("==="*19, "删除一个缓存服务器后~") print_pretty_dict( compute_cache_percentage_virtual_ring(cacher1.container, cacher2.container)) print("==="*19, "添加一个缓存服务器后~") print_pretty_dict( compute_cache_percentage_virtual_ring(cacher1.container, cacher3.container))
实现效果
python virtualconsisthash.py 25929580212780940911456562527067013 12101104964982711566768785763136289074 74170601562041857353724622613970855161 77290231086376083997830514397772133017 108956197245253243279835718906668306846 119181851294818588345880953329601308254 148120148621525998622527044630882426909 156975434986591250703568213828815453515 166356565783230552968534833801964089480 200325646817984951237589036984080642913 314164546590207529500398448833042413158 322409963387938480044046299781174104628 74170601562041857353724622613970855161: 192.168.0.1:11211#0 148120148621525998622527044630882426909: 192.168.0.1:11211#1 77290231086376083997830514397772133017: 192.168.0.1:11211#2 12101104964982711566768785763136289074: 192.168.0.2:11211#0 166356565783230552968534833801964089480: 192.168.0.2:11211#1 25929580212780940911456562527067013: 192.168.0.2:11211#2 119181851294818588345880953329601308254: 192.168.0.3:11211#0 156975434986591250703568213828815453515: 192.168.0.3:11211#1 108956197245253243279835718906668306846: 192.168.0.3:11211#2 200325646817984951237589036984080642913: 192.168.0.4:11211#0 314164546590207529500398448833042413158: 192.168.0.4:11211#1 322409963387938480044046299781174104628: 192.168.0.4:11211#2 192.168.0.1:11211#0: [] 192.168.0.2:11211#0: [{'a': 'a'}, {'h': 'h'}, {'j': 'j'}, {'l': 'l'}] 192.168.0.3:11211#0: [] 192.168.0.4:11211#0: [{'e': 'e'}, {'g': 'g'}, {'o': 'o'}, {'t': 't'}, {'v': 'v'}, {'x': 'x'}] 192.168.0.1:11211#1: [{'m': 'm'}] 192.168.0.2:11211#1: [{'b': 'b'}, {'d': 'd'}, {'f': 'f'}, {'i': 'i'}, {'k': 'k'}, {'p': 'p'}] 192.168.0.3:11211#1: [{'n': 'n'}, {'q': 'q'}, {'u': 'u'}] 192.168.0.4:11211#1: [{'w': 'w'}] 192.168.0.1:11211#2: [{'c': 'c'}, {'r': 'r'}, {'y': 'y'}] 192.168.0.2:11211#2: [{'s': 's'}] 192.168.0.3:11211#2: [] 192.168.0.4:11211#2: [{'z': 'z'}] 192.168.0.2:11211#0: [{'a': 'a'}, {'c': 'c'}, {'h': 'h'}, {'j': 'j'}, {'l': 'l'}, {'r': 'r'}, {'y': 'y'}] 192.168.0.3:11211#0: [{'m': 'm'}] 192.168.0.4:11211#0: [{'e': 'e'}, {'g': 'g'}, {'o': 'o'}, {'t': 't'}, {'v': 'v'}, {'x': 'x'}] 192.168.0.2:11211#1: [{'b': 'b'}, {'d': 'd'}, {'f': 'f'}, {'i': 'i'}, {'k': 'k'}, {'p': 'p'}] 192.168.0.3:11211#1: [{'n': 'n'}, {'q': 'q'}, {'u': 'u'}] 192.168.0.4:11211#1: [{'w': 'w'}] 192.168.0.2:11211#2: [{'s': 's'}] 192.168.0.3:11211#2: [] 192.168.0.4:11211#2: [{'z': 'z'}] 192.168.0.1:11211#0: [] 192.168.0.2:11211#0: [{'a': 'a'}] 192.168.0.3:11211#0: [] 192.168.0.4:11211#0: [{'g': 'g'}, {'v': 'v'}, {'x': 'x'}] 192.168.0.1:11211#1: [{'m': 'm'}] 192.168.0.2:11211#1: [{'b': 'b'}, {'d': 'd'}, {'f': 'f'}, {'i': 'i'}, {'k': 'k'}, {'p': 'p'}] 192.168.0.3:11211#1: [{'n': 'n'}, {'q': 'q'}, {'u': 'u'}] 192.168.0.4:11211#1: [{'w': 'w'}] 192.168.0.1:11211#2: [{'c': 'c'}, {'r': 'r'}, {'y': 'y'}] 192.168.0.2:11211#2: [{'s': 's'}] 192.168.0.3:11211#2: [] 192.168.0.4:11211#2: [{'z': 'z'}] 192.168.0.5:11211#0: [{'h': 'h'}, {'j': 'j'}, {'l': 'l'}] 192.168.0.5:11211#1: [{'e': 'e'}, {'o': 'o'}, {'t': 't'}] 192.168.0.5:11211#2: [] ========================================================= 删除一个缓存服务器后~ 192.168.0.1:11211: 4 192.168.0.2:11211: 8 192.168.0.3:11211: 3 192.168.0.4:11211: 5 ========================================================= 添加一个缓存服务器后~ 192.168.0.1:11211: 0 192.168.0.2:11211: 11 192.168.0.3:11211: 3 192.168.0.4:11211: 8
结果表明: 带有了虚拟节点的一致哈希实现,使得缓存的命中率得到了进一步的提高。而且平衡性也更趋于平和。
总结
通过上述分析,不难发现。
硬哈希适用场景为“稳定”的缓存服务群,因此实际生产环境不怎么被用到。
简单一致哈希,缓存命中率还算可以,但是缺乏平衡性,容易导致某台节点压力过大而有些节点空闲的状况。
带有虚拟节点的一致哈希可以很好的解决上面的两个问题,但是具体的虚拟节点的设置replicas可能还需要根据实际的生产环境来进行设置。以此来达到一个最优的效果。
-
基于模糊神经网络的高层次创新型科技人才的评价
2020-06-20 18:49:49为了提高高层次创新型科技人才的引进与管理的科学性,弥补高层次创新型科技人才评价中的不足,本研究首先根据高层次创新型科技人才的概念及特征设计了三个层次的评价指标,运用模糊层次分析法对三级评价指标进行筛选;... -
大学生党员的个人评价.doc
2021-01-18 18:56:27下面是小编带来的关于党员的个人评价的内容,欢迎阅读!大学生党员的个人评价篇一 思想上,积极进取,坚持对党的理论知识的学习,进一步提高自己的思想觉悟。切实执行党的纪律、国家的法律以及学校、学院的各项规章... -
一种改进的水环境质量模糊层次综合评价模型
2020-01-01 00:40:25一种改进的水环境质量模糊层次综合评价模型,褚克坚,华祖林,引入模糊一致矩阵概念,对传统层次分析法(AHP)进行改进,以解决判断矩阵一致性问题,并结合模糊评判法,建立了一种改进的水环境 -
SPA-ITFN耦合模型下的煤矿地下水质评价
2020-05-18 01:52:15提出用集对分析(SPA)多元联系数来描述煤矿水质评价中的确定性和模糊不确定性,并引入区间三角模糊数(ITFN)来对联系数同异反结构中差异度系数的连续变化过程进行描述,最后提出了基于多元联系数的区间三角模糊数的决策... -
“从事后到事前”的转变——谈粒数据的概念的影响力
2017-02-20 15:14:43如果从数据完整度或数据一致性的角度来说,很多垃圾数据的表现并不差,就算是考虑到数据与业务的相关性,那也是需要建模进行描述性统计分析,这其中的时间成本和人员素质要求可不低。 之前参加过几次信标委的数据...最近在写关于数据质量的文档,一直在脑中有个问题,数据到底怎么给评价质量乃至数据价值?如果从数据完整度或数据一致性的角度来说,很多垃圾数据的表现并不差,就算是考虑到数据与业务的相关性,那也是需要建模进行描述性统计分析,这其中的时间成本和人员素质要求可不低。之前参加过几次信标委的数据标准研讨会,出席的专家大部分时间所讨论的,于我上面所讲的数据质量分析方法并无本质的区分。更有位中科院专门研究数据质量的专家称,数据质量不可严密考证,因为数据价值不可估量。是的,我非常同意数据价值要通过数据质量来体现这个观点,激进一点说,考虑到数据复制成本几乎为零,对照商品质量与商品价格的关系,可以认为数据质量等同于数据价值。但我们已经知道,数据价值并不是依靠数据本身来实现的,数据与其他的数据进行关联,做成产品,能够应用开来,解决业务痛点,数据的价值必须要升华为一种服务的能力。质量再高的数据如果没找到合适的应用途径,也是无用;我们可以给服务定价,但数据本身,是很难定价的。考虑到一种情况,如果数据在被生产的同时,已经带有了场景属性呢?比如说,一次购物行为,涉及到的对象:顾客、商家、银行,关键点:商品、网页点击、物流、顾客满意度等。暂且不问这些数据是怎么汇集起来的,光看结果,这个完整的数据集质量,其实是很高的。它几乎可以拿来就用,还可以相互比对,交叉验证等。可以说,这个数据集在质量上是接近完美的(考虑到数据采集的误差和人类参与整理的不可预知风险)。这就是中国大数据技术与应用联盟副理事长赵平生先生提出的粒数据概念,我把它做了下延伸。粒数据最大的革新在于,它让数据质量管理从事后转向了“事前”,严格地说应该是事中,事情发生过程中。再也不要面对数据的质量管理,而是数据产生参与各方的同心协力,“以合法、合规的方式产生一条真实的电子数据...一旦产生即不可被修改”。听听,是不是觉得有点像区块链技术?去中心化的记录,可扩展、安全可靠等,与其靠一个人来搜集维护,不如大家一起,形成一个联合共享式的数据仓库。粒数据一旦产生,将产生连锁效应,其联结的范围可以扩充至全世界、联结的深度可以贯穿全行业。它的魅力如此之大,以至于每家企业共享出来的数据可以得到潜在的几倍乃至几百倍的业务收益回赠。粒数据一出现,天然就带有革*min的诉求,它甚至带有某种共产主义的特质,一起劳动、一起收获,没有垄断和私自占有,全社会合作化大生产,听起来,很美好不是吗?这也是粒数据或者说是区块链的局限之处,为什么?有利益的地方就有人的“贪心”在作怪。参照比特币的安全性,区块链从技术上来说是接近完美的,然而,对于面向应用的区块链,一旦其赖以生存的加密机制被暴力破解或者某些参与者人为恶意制造假数据,致使整个区块链的参与者都要承担巨大的风险。看看各大金融机构对区块链的态度,基本都是在做前沿调研,谁也不敢真放开了做落地。没有绝对的安全,只有绝对的利益,从数据共享开放回滚到封闭自足,技术恐怕从来都不是决定因素。粒数据的概念,应该说是很超前的。就算在当下,市场监管和经济环境支撑不起粒数据的全面应用,在某些特定的领域,粒数据还是具有相当大的启发性的:比如说政府部门和企业内部,以产生数据的事件为一个集合,形成大数据应用的基本数据单位,而不是之前,把数据采集完了之后再去做关联。同时,这也有助于引导我们养成数据思维的好习惯。参考资料:区块链将彻底改变人工智能 | 熵、区块链和人工智能一文详解“粒数据”-大数据领域最新研究成果《DAMA数据管理知识体系指南》,p214-p230 -
基于JAVA WEB的AHP层次分析法实践--概念
2018-05-28 13:14:03什么是层次分析法?层次分析法,是应用网络系统理论和多目标综合...运用层次分析法构造系统模型时,大体可以分为以下五个步骤:建立层次结构模型构造判断矩阵一致性检验计算各层权重总体一致性检验层次分析法的优点... -
深挖用户体验:如何评价用户体验的好与坏
2021-02-21 02:01:17保持界面的一致性。用户界面设计在工作流程上分为结构设计、交互设计、视觉设计三个部分。结构设计也称概念设计(ConceptualDesign),是界面设计的骨架。通过对用户研究和任务分析,制定出产品的整体架构。交互设计的... -
导光板发光质量评价与优化设计
2021-01-27 07:21:31以灰度直方图表征光能分布, 进而给出均匀度的评判公式, 提出了均匀度评判精度P的概念, 并且通过编程给出离散灰度级所对应的网点位置, 从而实现精准优化。以184 mm×314 mm×0.55 mm的导光板为例进行仿真验证, 针对... -
通信规约相关概念
2015-12-01 14:20:16规约性能评价标准:数据完整性、数据一致性、传输速率平衡传输(Balanced Transmission):没有主从之分,通信双方都可以启动报文传输。如对于平衡103而言,主站(不再是严格意义上的主站)可以定时启动总召、广播校... -
论文研究-多源评价中信息标准化研究.pdf
2019-09-06 18:51:26在重述过程中,如果不相似性度量保持一致,那么信息标准化过程就可以保持语言值的语义不变。在现有许多文献中,对于标准语言值集合的选取规则并未做过多的要求,只是设定此集合的势在7到13之间。为了进一步控制语言... -
学习常用模型及算法:3.评价和预测
2020-07-31 22:32:53经过计算得出一致性比例。 将最大特征值所对应的特征向量归一化,即可得到本层次各因素的重要性的排序。 求出准则层对目标层的权重之后,我们再去求备选层对准则层的权重,方法同前述一致。 将两个步. -
论文研究-基于FAHP和FMCDM构建软件可信性评估模型.pdf
2019-07-22 17:57:48首先针对软件可信性没有一致定义的现状,提出了相对可信性的概念;接着基于模糊数理论,用三角模糊数表示专家评估中语言变量的主观性和模糊性,结合专家给出的模糊指标权重及待评软件可信等级的模糊评价,得到软件... -
简图记录-LCD显示图像评价基础
2018-11-29 23:50:34简图记录总结~ 一、概念 LCD:liquid Crystal Display,液晶显示器。... 液晶:具有液体的流动特性,同时具有晶体的各向性、双折射等特性。 偏振片:一种透光片,只有偏振方向一致的光波... -
层次分析法的理解
2020-08-07 11:39:31一致矩阵的特点:一致矩阵的引理:一致性检验的步骤判断矩阵计算权重算术平均法求权重几何平均法特征值法求权重层次分析法的局限性层次分析法框架图 层次分析法 评价类问题可用打分来解决,也就是说通过分数来量化一... -
论文研究-基于概率不确定犹豫模糊偏好关系的决策模型.pdf
2019-09-11 19:21:16针对犹豫模糊信息在现实决策中难以准确和充分的提供决策者评价信息的问题,引入了概率不确定犹豫模糊偏好关系(PUHFPR)的概念,其能够有效处理概率不确定犹豫模糊元(PUHFE)中元素发生概率信息部分已知和完全未知... -
柯尔特教程 CoRT 创造性思维
2009-03-15 00:18:28检验概念的“唯一性”会导致用另外的方式做事。 第5课:支配性观点。大多数情况下都有占统治地位的观点。为了具有创造性,必须摆脱这些观点的束缚。 第6课:定义问题。对问题进行定义会使它更容易解决。 第7课:剔除... -
基于区间直觉模糊数的水利工程评标研究
2020-06-17 05:40:45以一个水利工程评标为例进行分析,计算结果最佳方案(即最优投标单位)是A4,最劣的方案为A1,表明利用该模型对水利工程评标中的各投标方案进行优选具有一定的操作性,而且利用该方法得出的评价结果与实际情况比较一致。 -
论文研究-房地产景气预警中DI的改进及与CI的精度比较研究.pdf
2019-09-20 12:47:46在运用景气指数法预警、计算扩散指数 DI和合成指数 CI时 ,往往存在警度不一致并导致警情失真等弊端 ,直接影响到景气评价的科学性 .在对传统 DI计算方法进行合理改进的... -
论文研究-基于均匀置乱的图像位置置乱衡量方法.pdf
2019-09-12 19:23:09由于图像置乱分成位置和像素值置乱两类,图像置乱衡量也从这两方面进行分析。...通过对大量实验结果的分析得出,该衡量算法可以准确地衡量图像置乱程度,与人的视觉评价保持一致,具有可行性和有效性。 -
我国GIS软件的发展现状
2008-10-27 20:55:07近年来,国外GIS与数据库开发商加紧了联合的步伐,共同开发全关系的GIS软件,使GIS软件能充分利用商用数据库中已经成熟的众多特性,如内存缓冲、快速索引、数据完整性和一致性保证、并发控制、安全和恢复机制及... -
测试基础 软件质量
2015-09-01 19:42:042.软件质量的概念 ISO/IEC9126规定,软件质量可用6个特性来评价: 功能性:软件所实现的功能达到它的设计规范和满足用户需求的程度 可靠性:在满足一定条件的应用环境中,软件能够正常维持其工作的能力 可用性:... -
论文研究-人因分析:需要、问题和发展趋势.pdf
2019-09-20 12:19:39客观性与一致性 ;数据的可用性 ;文化因素 ;组织管理层的人因分析 .最后从理论与应用两方面讨论了人因分析学科近期应发展的三个范畴 :人因分析基础研究 ;人 -机系统设计指导 ;安全评价与事故防范 . -
交互设计
2020-06-02 09:20:02设计目标可用性设计原则可视化屏幕元素的选择、布局、呈现及装饰一致性直接映射有效反馈良好的GUI设计原则设计过程Design(设计)Prototype(原型)Evaluation(评价) 基本概念 软件设计= 编码设计 + 交互设计... -
微服务之构建容错&自动降级的系统
2020-12-26 14:05:06SOA在十年前就提出了服务化的概念,那微服务到底是新的理论突破,还是新瓶装旧酒换了一个概念出来忽悠? 总结了微服务应该具备的特点: - 小, 且专注于做⼀件事情 - 独立的进程 - 松耦合、... -
软件工程知识点
2012-12-02 21:34:25比较常用的需求有效性验证方法与工具包括:需求评审、需求原型评价和基于CASE工具的需求一致性分析。 6.需求规格定义 需求规格说明书是需求分析阶段需要交付的基本文档,将成为开发者进行软件设计和用户进行软件验证...
-
C/C++ FIFO queue - 先进先出队列
-
STM32F373XXDataSheet.zip
-
美图大数据平台架构实践
-
C++代码规范和Doxygen根据注释自动生成手册
-
Spring学习笔记之Spring HelloWorld
-
MySQL Router 实现高可用、负载均衡、读写分离
-
leetcode算法第7题
-
Kubernetes下日志采集、存储与处理技术实践
-
自适应极限学习机
-
2014年下半年 信息系统监理师 上午试卷 综合知识 软考真题【含答案和答案解析】
-
FyreString:FyreString是PHP的免费开源字符串实用程序库-源码
-
基于Qt的LibVLC开发教程
-
微博时间格式转换
-
基于电商业务的全链路数据中台落地方案(全渠道、全环节、全流程)
-
Spring学习笔记之IOC与DI概述
-
关于绝热演化的一般模型
-
FastDFS 分布式文件系统部署
-
java数独题库高效生成算法代码
-
基于Flink+Hudi构建企业亿级云上实时数据湖教程(PC、移动、小
-
2011年下半年 信息系统监理师 上午试卷 综合知识 软考真题【含答案和答案解析】