WenLiangBaoBlog

个人博客


  • 首页

  • 标签7

  • 归档62

  • 搜索

mysql

发表于 2024-03-16

mysql结构

mysql索引

索引概述

MySQL官方对索引的定义为:索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据
库系统还维护者满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据, 这样就可以在这些数
据结构上实现高级查找算法,这种数据结构就是索引。如下面的示意图所示 :

左边是数据表,一共有两列七条记录,最左边的是数据记录的物理地址(注意逻辑上相邻的记录在磁盘上也并不是一定物理相邻的)。为了加快Col2的查找,可以维护一个右边所示的二叉查找树,每个节点分别包含索引键值和一个指向对应数据记录物理地址的指针,这样就可以运用二叉查找快速获取到相应数据。
一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上。索引是数据库中用来提高性能的最常用的工具。

索引的优劣势

优势
1 ) 类似于书籍的目录索引,提高数据检索的效率,降低数据库的IO成本。
2 ) 通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗。

劣势
1 ) 实际上索引也是一张表,该表中保存了主键与索引字段,并指向实体类的记录,所以索引列也是要占用空间
的。
2 ) 虽然索引大大提高了查询效率,同时却也降低更新表的速度,如对表进行INSERT、 UPDATE、 DELETE。因为
更新表时, MySQL 不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所
带来的键值变化后的索引信息。

索引结构

索引是在MySQL的存储引擎层中实现的,而不是在服务器层实现的。所以每种存储引擎的索引都不一定完全相同,也不是所有的存储引擎都支持所有的索引类型的。 MySQL目前提供了以下4种索引:

​ BTREE 索引 : 最常见的索引类型,大部分索引都支持 B 树索引。
​ HASH 索引:只有Memory引擎支持 , 使用场景简单 。
​ R-tree 索引(空间索引):空间索引是MyISAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少,不做特别介绍。
​ Full-text (全文索引) :全文索引也是MyISAM的一个特殊索引类型,主要用于全文索引,I nnoDB从
​ Mysql5.6版本开始支持全文索引。

我们平常所说的索引,如果没有特别指明,都是指B+树(多路搜索树,并不一定是二叉的)结构组织的索引。其中
聚集索引、复合索引、前缀索引、唯一索引默认都是使用 B+tree 索引,统称为 索引。

freemarker

发表于 2024-01-20

CPU架构

发表于 2022-08-15

概述

CPU架构是CPU商给CPU产品定的一个规范,主要目的是为了区分不同类型的CPU。

目前市场上的CPU分类主要分有两大阵营,一个是intel、AMD为首的复杂指令集CPU,另一个是以IBM、ARM为首的精简指令集CPU。不同品牌的CPU,其产品的架构也不相同。Intel、AMD的CPU是X86架构,IBM公司的CPU是PowerPC架构,ARM公司的CPU是ARM架构,国内的飞腾CPU也是ARM架构。此外还有MPIS架构、SPARC架构、Alpha架构

主流架构

目前cpu主流架构有 X86、ARM、MPIS、SPARC、Alpha

x86

X86架构(The X86 architecture)是微处理器执行的计算机语言指令集。X86指令集是美国Intel公司为其第一块16位CPU(i8086)专门开发的。

美国IBM公司1981年推出的世界第一台PC机中的CPU–i8088(i8086简化版)使用的也是X86指令。同时电脑中为提高浮点数据处理能力而增加的X87芯片系列数字协处理器则另外使用X87指令,包括后来 Intel 80186、80286、80386以及80486,由于以“86”作为结尾,以后就将X86指令集和X87指令集统称为X86指令集。虽然随着CPU技术的不断发展,Intel陆续研制出更新型的i80386、i80486直到今天的Pentium 4(以下简为P4)系列,但为了保证电脑能继续运行以往开发的各类应用程序以保护和继承丰富的软件资源,所以Intel公司所生产的所有CPU仍然继续使用X86指令集,所以它的CPU仍属于X86系列。

x86架构CPU主要应用领域:个人计算机、服务器等。在PC端市场Wintel组合(windows系统 + intel处理器)占据了大部分江山,另外一部分有ADM占领。

目前国内有兆芯,从AMD和VIA获取授权,研发自己的X86CPU,有其它国产CPU + 国产操作系统(linux系)可以用于教育和事业单位以及军工行针对的是特殊用户,国产CPU和操作系统想进入民用市场,由于性能、价格以及生态系统等,仍需要继续优化打磨以及一个合适契机。

X86指令集发展

IA:Intel(英特尔)处理器的服务器称之为IA(Intel Architecture)架构服务器

IA-32:英特尔32位体系架构,X86从16位到32位是在原有的架构基础上进行修改(Intel称之为IA-32)

x86-32:现如今Intel把x86-32称为IA-32

x86-64:分为intel和AMD

AMD64:x86架构的64位拓展,向后兼容于16位及32位的x86架构。x64于1999年由AMD设计,AMD首次公开64位集以扩展给x86,称为“AMD64”,AMD64和Intel64基本上一致

Intel64:EM64T(Extended Memory 64 Technology)扩展64bit内存技术,本质上和AMD64一样都是IA-32的增强版本。

IA-64:64位的英特尔架构,英特尔安腾架构(Intel Itanium architecture),使用在Itanium处理器家族上的64位指令集架构,由英特尔公司与惠普公司共同开发。IA是Intel Architecture(英特尔架构)的缩写,64指64位系统。使用这种架构的CPU,包括Itanium和Itanium 2。此架构与x86及x86-64并不相容,操作系统与软件需使用IA-64专用版本。

Intel推出X86架构已满40年了,同486相比,Pentium向前迈进了一大步, 而PⅡ的前进步伐则没有这么大了,X86 CPU的发展似乎已到了尽头。英特尔非常清楚,是X86指令集限制了CPU性能的进一步提高,因此,他们正同惠普共同努力开发下一代指令集架构(Instruction Set Architecture ,ISA): EPIC(Explicitly Parallel Instruction Computing,显性并行指令计算)。对英特尔而言, IA-64(英特尔的64位架构)是下一个10到15年的架构。新的ISA将使英特尔摆脱X86架构的限制,从而设计出超越所有现有RISC CPU和X86 CPU的新型处理器。

ARM架构

ARM架构,也称作进阶精简指令集机器(Advanced RISC Machine,更早称作:Acorn RISC Machine),是一个32位精简指令集(RISC)处理器架构。其广泛地使用在许多嵌入式系统上。由于节能的特点,ARM处理器非常适用于行动通讯领域,符合其主要设计目标为低耗电的特性。

目前,ARM家族占了所有32位嵌入式处理器75%的比例,使它成为占全世界最多数的32位架构之一。ARM处理器可以在很多消费性电子产品上看到,从可携式装置(PDA、移动电话、多媒体播放器、掌上型电子游戏,和计算机)到电脑外设(硬盘、桌上型路由器)甚至在导弹的弹载计算机等军用设施中都有他的存在。在此还有一些基于ARM设计的派生产品,重要产品还包括Marvell的XScale架构和德州仪器的OMAP系列。

ARM 授权方式:ARM 公司本身并不靠自有的设计来制造或出售 CPU ,而是将处理器架构授权给有兴趣的厂家。ARM 提供了多样的授权条款,包括售价与散播性等项目。对于授权方来说,ARM 提供了 ARM 内核的整合硬件叙述,包含完整的软件开发工具(编译器、debugger、SDK),以及针对内含 ARM CPU 硅芯片的销售权。

对于无晶圆厂的授权方来说,其希望能将 ARM 内核整合到他们自行研发的芯片设计中,通常就仅针对取得一份生产就绪的智财核心技术(IP Core)认证。对这些客户来说,ARM 会释出所选的 ARM 核心的闸极电路图,连同抽象模拟模型和测试程式,以协助设计整合和验证。

需求更多的客户,包括整合元件制造商(IDM)和晶圆厂家,就选择可合成的RTL(暂存器转移层级,如 Verilog)形式来取得处理器的智财权(IP)。借着可整合的 RTL,客户就有能力能进行架构上的最佳化与加强。这个方式能让设计者完成额外的设计目标(如高震荡频率、低能量耗损、指令集延伸等)而不会受限于无法更动的电路图。虽然 ARM 并不授予授权方再次出售 ARM 架构本身,但授权方可以任意地出售制品(如芯片元件、评估板、完整系统等)。商用晶圆厂是特殊例子,因为他们不仅授予能出售包含 ARM 内核的硅晶成品,对其它客户来讲,他们通常也保留重制 ARM 内核的权利。

国外生产厂商:TI (德州仪器)、Samsung(三星)、Freescale(飞思卡尔)、Marvell(马维尔)、Nvidia(英伟达)、Qualcomm(高通)、STMicroelectronics(意法半导体)。

国内生产厂商:华为(海思芯片)、飞腾(FT-1500、FT2000-4等CPU芯片)、兆易创新(GD32系列MCU,参考STM32系列)、瑞芯微(RK系列芯片)、联发科(台湾,天玑系列)。

ARM架构的CPU可以有多核,例如几年前联发科推出10核处理器Helio X20(被戏称一核有难,八核围观,国产FT处理器已经推出了16核处理器。但是由于ARM自身低功耗等因素的限制,核心数多并不一定能大大提升性能。

目前ARM主要市场是手机端CPU和MCU,手机CPU市场,由高通骁龙系列、华为麒麟系列、以及三星猎户系列和联发科系列,在MCU端主要是STM32以及国产的GD32,其它厂商的芯片用于其它领域,比如汽车电子、智能家居等。在CPU处理器上,有华为海思的鲲鹏920CPU(应用于泰山服务器中)和FT的CPU(军工领域),虽然FT的CPU起步很早,但是鲲鹏显然有后来居上之趋势。国内ARM芯片做的最好的是华为海思,鲲鹏920CPU性能在ARM架构中是NO1,另外海思麒麟系列手机芯片已发展为全球前三的地位,海思的视频处理芯片以及IoT芯片,在行业中都是标杆的产品。

在2020年11月11日,apple公司发布了新一代的mac book,亮点就是使用了apple自己的ARM架构的M1。由于ARM的功耗小,在新一代的macbook上,apple大胆的去掉了散热风扇芯片,将笔记本厚度进一步压缩,续航时间达到了18小时。同时,搭载M1芯片的mac book CPU 性能提升至 3.5 倍,GPU 性能提升至 5 倍,机器学习性能提升至 9 倍。根据apple公司的影响力,未来PC中市场将会被ARM架构的CPU替代。

MPIS架构

MIPS是世界上很流行的一种RISC处理器。MIPS的意思是“无内部互锁流水级的微处理器”(Microprocessor without interlockedpipedstages),其机制是尽量利用软件办法避免流水线中的数据相关问题。它最早是在80年代初期由斯坦福(Stanford)大学Hennessy教授领导的研究小组研制出来的。MIPS公司的R系列就是在此基础上开发的RISC工业产品的微处理器。这些系列产品为很多计算机公司采用构成各种工作站和计算机系统。

MIPS技术公司是美国著名的芯片设计公司,它采用精简指令系统计算结构(RISC)来设计芯片。和英特尔采用的复杂指令系统计算结构(CISC)相比,RISC具有设计更简单、设计周期更短等优点,并可以应用更多先进的技术,开发更快的下一代处理器。MIPS是出现最早的商业RISC架构芯片之一,新的架构集成了所有原来MIPS指令集,并增加了许多更强大的功能。MIPS自己只进行CPU的设计,之后把设计方案授权给客户,使得客户能够制造出高性能的CPU。

1984年,MIPS计算机公司成立,开始设计RISC处理器;

1986年推出R2000处理器。

1988年推R3000处理器。

1991年推出第一款64位商用微处器R4000;之后又陆续推出R8000(于1994年)、R10000(于1996年)和R12000(于1997年)等型号。

1992年,SGI收购了MIPS计算机公司。

1998年,MIPS脱离SGI,成为MIPS技术公司;随后,MIPS公司的战略发生变化,把重点放在嵌入式系统;1998年-MIPS科技股票在美国纳斯达克股票交易所公开上市。

1999年,MIPS公司发布MIPS32和MIPS64架构标准,为未来MIPS处理器的开发奠定了基础。新的架构集成了所有原来NIPS指令集,并且增加了许多更强大的功能。

MIPS公司陆续开发了高性能、低功耗的32位处理器内核(core)MIPS324Kc与高性能64位处理器内核MIPS645Kc。

2000年,MIPS公司发布了针对MIPS32 4Kc的版本以及64位MIPS 64 20Kc处理器内核。

2007年8月16日-MIPS科技宣布,中科院计算机研究所的龙芯中央处理器获得其处理器IP的全部专利和总线、指令集授权。

2007年12月20日-MIPS科技宣布,扬智科技已取得其针对先进多媒体所设计的可定制化系统单芯片(SoC)核心“MIPS32 24KEcPro”授权。

MPIS架构授权和ARM架构授权不一样,ARM架构授权用户基本不能自行修改,而MPIS架构授权后,可以自己修改。目前MPIS发扬光大寄希望中科龙芯公司,龙芯处理器从龙芯1号,到现在的龙芯3号系列的3A4000,CPU的性能已经大幅度提高,在完全可以胜任日常办公或者作为特殊用途的服务器。龙芯CPU和国产的飞腾(FT)处理器并驾齐驱,发展我国自主可控CPU。

PowerPC系列

PowerPC 是一种精简指令集(RISC)架构的中央处理器(CPU),其基本的设计源自IBM(国际商用机器公司)的IBMPowerPC 601 微处理器POWER(PerformanceOptimized With Enhanced RISC;《IBM Connect 电子报》2007年8月号译为“增强RISC性能优化”)架构。二十世纪九十年代,IBM(国际商用机器公司)、Apple(苹果公司)和Motorola(摩托罗拉)公司开发PowerPC芯片成功,并制造出基于PowerPC的多处理器计算机。PowerPC架构的特点是可伸缩性好、方便灵活。

PowerPC 处理器有广泛的实现范围,包括从诸如 Power4 那样的高端服务器CPU 到嵌入式 CPU 市场(任天堂Gamecube 使用了 PowerPC)。PowerPC处理器有非常强的嵌入式表现,因为它具有优异的性能、较低的能量损耗以及较低的散热量。除了象串行和以太网控制器那样的集成 I/O,该嵌入式处理器与“台式机”CPU 存在非常显著的区别。

SPARC架构

SPARC架构(Scalable Processor ARChitecture,可扩展处理器架构)是国际上流行的RISC处理器体系架构之一,SPRAC如今已发展成为一个开放的标准,任何机构或个人均可研究或开发基于SPRAC架构的产品,而无需交纳版权费。SPARC 处理器架构具备精简指令集(RISC)、支持32 位/64 位指令精度,架构运行稳定、可扩展性优良、体系标准开放等特点。SPARC因此得以迅速发展壮大,在现在已经有大约3万多个成功的应用案例。

SPARCV7/V8 是目前嵌入式控制系统常用的处理器标准版本,并在航天设备的电子系统中得到广泛应用。然而,SPARC只是一个处理器的架构标准,并不提供现成的源码或IP核,具体的芯片实现要由开发者去完成。

运行Oracle Solaris的Oracle SPARC T4服务器提供了创世界纪录的性能,其单线程性能提高了5倍、内存容量高达2 TB且实现了极高的系统吞吐量和I/O容量。SPARC T4服务器适用于需要极高的可靠性、可用性和集成式片上加密加速的企业应用程序和任务关键型应用程序,可确保最终的安全性。

AIpha架构

Alpha处理器最早由DEC公司设计制造,在Compaq(康柏)公司收购DEC之后,Alpha处理器继续得到发展,并且应用于许多高档的Compaq服务器上。自1995年开始开发了21164芯片,那时的工艺为0.5um,主频为200MHz。1998年,推出新型号21264,当时的主频是600MHz。较新的21264芯片主频达到1GHz,工艺为0.18um。在该芯片具有完善的指令预测能力和很高的存储系统带宽(超过1GB/s),并且其中增加了处理视频信息的功能,其多媒体处理能力得到了增强。

Alpha架构于1992年2月25日,在东京召开的一次会议上面被正式推介,新架构的关键特性都一一的被罗列出来。当时说Alpha只是产品开发的内部代号。新处理器采用完全64-bit RISC设计,执行固定长度指令(32 bits)。有32个64 bit整数寄存器,操作43-bit的虚拟地址(在后来能够扩充到64-bit)。和VAX相同,使用little-endian字节顺序,即低字节的寄存器占用低内存地址线。而不像如摩托罗拉等大多数处理器所使用的big-endian字节顺序,即低字节寄存器占用高内存地址线。除此之外,处理器还内建一个算术协处理器,有32个浮点64-bit寄存器,采用随机存取,而不是在intel x86协处理器上使用的堆栈存取方式。整个Alpha的生命周期被设计为至少25年。

Alpha处理器被用于DEC自己的工作站和服务器中。作为VAX的后续被开发,支持VMS操作系统,如 Digital UNIX。不久之后开放源代码的操作系统也可以在其上运行,如Linux和 DSB 。Microsoft 支持这款处理器,直到Windows NT 4.0 SP6 ,但是从Windows 2000 RC2开始放弃了对Alpha的支持。

目前国内采用此架构的是申微超算处理器,得益于国家的支持,申威处理器在军队应用广泛。

jdk新特性

发表于 2022-06-18

jdk 7

try 语法使用

try后面跟()括号,用来管理释放资源,try括号内的资源会在try语句结束后自动释放,前提是这些可关闭资源必须实现 java.lang.AutoCloseable接口

templet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.download;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class WordCount {
public static void main(String[] args) {
try (
InputStream in = new FileInputStream("");
OutputStream out = new FileOutputStream("");
)
{
byte[] buf = new byte[8192];
int i;
while ((i = in.read(buf)) != -1) {
out.write(buf, 0, i);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

Dubbo

发表于 2022-06-09

windows常用cmd命令汇总

发表于 2022-06-08

Windows 常用CMD汇总

端口

1
netstat -ano | findstr <端口>

例子

1
2
3
4
5
6
7
8
9
10
11
C:\Users\spider>netstat -ano|findstr 88
TCP 0.0.0.0:5040 0.0.0.0:0 LISTENING 11788
TCP 127.0.0.1:8588 0.0.0.0:0 LISTENING 6140
TCP 127.0.0.1:8588 127.0.0.1:49886 ESTABLISHED 6140
TCP 127.0.0.1:8588 127.0.0.1:59734 ESTABLISHED 6140
TCP 127.0.0.1:49886 127.0.0.1:8588 ESTABLISHED 18840
TCP 127.0.0.1:59734 127.0.0.1:8588 ESTABLISHED 6140
TCP 127.0.0.1:59888 127.0.0.1:63342 ESTABLISHED 12328
TCP 127.0.0.1:63342 127.0.0.1:59888 ESTABLISHED 6968
UDP 0.0.0.0:5050 *:* 11788
UDP 0.0.0.0:52088 *:* 6764

公式计算器实现

发表于 2022-06-07

目标:

​ 实现一个简易的公式计算器,如根据用户输入 2+4*3-2-(2*8) 公式可以自行求解

实现思路:

​ 概念:

​ 中缀式:如2+4*3-2-(2*8)

​ 后缀式:如上中缀式转换为后缀式为

1. 公式转换,解决公式开头为负数的问题。
1. 将中缀式转换为后缀式并放入后缀栈中
1. 将后缀栈中的数据弹出计算并放入结果栈中

逆波兰(中缀转后缀式)总结:

  1. 从左往右依次处理

  2. 遇见数字直接追加写入公式中,如果遇见的是运算符。

    2.1 遇见的运算符与栈顶中的运算符进行优先级对比,如栈中不存在运算符则直接放入栈中,优先级小于等于栈顶运算符时循环取出栈顶运算符追加入公式中,最后将当前运算符放入栈中。优先级大于栈顶运算符时直接放入栈中。

    2.2 遇见的运算符为)时,依次弹出栈顶运算符并追加入公式中,直至栈顶的运算符为(时为止。

代码核心组件逻辑图

  • 公式计算器
    • 解析器(逆波兰/后缀表达式)
      • 后缀式栈
      • 运算符号栈
      • 计算栈
    • 函数集
      • 常用的数学函数
        • 加
        • 减
        • 乘
        • 除

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package com.spidermen.math;

import java.math.BigDecimal;
import java.math.RoundingMode;

public class BaseMethod {
// 默认除法运算精度
private static final int DEF_DIV_SCALE = 2;

// 这个类不能实例化
private ArithHelper() {
}

/**
* 提供精确的加法运算。
*
* @param v1 被加数
* @param v2 加数
* @return 两个参数的和
*/
public static double add(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.add(b2).doubleValue();
}

public static double add(String v1, String v2) {
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.add(b2).doubleValue();
}

/**
* 提供精确的减法运算。
*
* @param v1 被减数
* @param v2 减数
* @return 两个参数的差
*/
public static double sub(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.subtract(b2).doubleValue();
}

public static double sub(String v1, String v2) {
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.subtract(b2).doubleValue();
}

/**
* 提供精确的乘法运算。
*
* @param v1 被乘数
* @param v2 乘数
* @return 两个参数的积
*/
public static double mul(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.multiply(b2).doubleValue();
}

public static double mul(String v1, String v2) {
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.multiply(b2).doubleValue();
}

/**
* 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入。
*
* @param v1 被除数
* @param v2 除数
* @return 两个参数的商
*/
public static double div(double v1, double v2) {
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return div(b1, b2, DEF_DIV_SCALE);
}

public static double div(String v1, String v2) {
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return div(b1,b2,DEF_DIV_SCALE);
}

/**
* 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。
*
* @param v1 被除数
* @param v2 除数
* @param scale 表示表示需要精确到小数点以后几位。
* @return 两个参数的商
*/
public static double div(BigDecimal v1, BigDecimal v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
return v1.divide(v2, scale, RoundingMode.HALF_UP).doubleValue();
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
package com.spidermen.math;


import com.alibaba.fastjson.JSONArray;

import java.util.Collections;
import java.util.Stack;

/**
* 数学表达式计算核心功能
*/
public class Calculator {
private Stack<String> postfixStack = new Stack<String>();
// 后缀式栈
private Stack<Character> opStack = new Stack<Character>();
// 运算符栈
private int[] operatPriority = new int[]{0, 3, 2, 1, -1, 1, 0, 2};

// 运用运算符ASCII码-40做索引的运算符优先级
public static double conversion(String expression) {
// log.info("公式[{}]开始计算!",expression);
double result = 0;
Calculator cal = new Calculator();
try {
expression = transform(expression);
result = cal.calculate(expression);
} catch (Exception e) {
e.printStackTrace();
// 运算错误返回0
return 0;
}
// return new String().valueOf(result);
// log.info("公式[{}]计算结果为:{}",expression,result);
return result;
}

/**
* 将表达式中负数的符号更改
*
* @param expression 例如-2+-1*(-3E-2)-(-1) 被转为 ~2+~1*(~3E~2)-(~1)
* @return
*/
private static String transform(String expression) {
char[] arr = expression.toCharArray();
for (int i = 0; i < arr.length; i++) {
if (arr[i] == '-') {
if (i == 0) {
arr[i] = '~';
} else {
char c = arr[i - 1];
if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == 'E' || c == 'e') {
arr[i] = '~';
}
}
}
}
if (arr[0] == '~') {
arr[0] = '-';
return "0" + new String(arr);
}
int i=0;
while (arr[i] =='('){
i++;
}
if(arr[i]=='-'){
return new String(arr,0,i)+"0"+new String(arr,i,arr.length-i);
}else {
return new String(arr);
}

}

/**
* 按照给定的表达式计算
*
* @param expression 要计算的表达式例如:5+12*(3+5)/7
* @return
*/
public double calculate(String expression) {
Stack<String> resultStack = new Stack<String>();
prepare(expression);
Collections.reverse(postfixStack);
// 将后缀式栈反转
String firstValue, secondValue, currentValue;
// 参与计算的第一个值,第二个值和算术运算符
while (!postfixStack.isEmpty()) {
currentValue = postfixStack.pop();
if (!isOperator(currentValue.charAt(0))) {
// 如果不是运算符则存入操作数栈中
currentValue = currentValue.replace("~", "-");
resultStack.push(currentValue);
} else {
// 如果是运算符则从操作数栈中取两个值和该数值一起参与运算
secondValue = resultStack.pop();
firstValue = resultStack.pop();
// 将负数标记符改为负号
firstValue = firstValue.replace("~", "-");
secondValue = secondValue.replace("~", "-");
String tempResult = calculate(firstValue, secondValue, currentValue.charAt(0));
resultStack.push(tempResult);
}
}
return Double.valueOf(resultStack.pop());
}

/**
* 数据准备阶段将表达式转换成为后缀式栈
*
* @param expression
*/
private void prepare(String expression) {
System.out.println("中缀式为: "+expression);
opStack.push(',');
// 运算符放入栈底元素逗号,此符号优先级最低
char[] arr = expression.toCharArray();
int currentIndex = 0;
// 当前字符的位置
int count = 0;
// 上次算术运算符到本次算术运算符的字符的长度便于获取之间的数值
char currentOp, peekOp;
// 当前操作符和栈顶操作符
for (int i = 0; i < arr.length; i++) {
currentOp = arr[i];
if (isOperator(currentOp)) {
// 如果当前字符是运算符
if (count > 0) {
postfixStack.push(new String(arr, currentIndex, count));
// 取两个运算符之间的数字
}
peekOp = opStack.peek();
if (currentOp == ')') {
// 遇到反括号则将运算符栈中的元素移除到后缀式栈中直到遇到左括号
while (opStack.peek() != '(') {
postfixStack.push(String.valueOf(opStack.pop()));
}
opStack.pop();
} else {
while (currentOp != '(' && peekOp != ',' && compare(currentOp, peekOp)) {
postfixStack.push(String.valueOf(opStack.pop()));
peekOp = opStack.peek();
}
opStack.push(currentOp);
}
count = 0;
currentIndex = i + 1;
} else {
count++;
}
}
if (count > 1 || (count == 1 && !isOperator(arr[currentIndex]))) {
// 最后一个字符不是括号或者其他运算符的则加入后缀式栈中
postfixStack.push(new String(arr, currentIndex, count));
}
while (opStack.peek() != ',') {
postfixStack.push(String.valueOf(opStack.pop()));
// 将操作符栈中的剩余的元素添加到后缀式栈中
}

System.out.println("后缀式为: "+ JSONArray.toJSONString(postfixStack));
}

/**
* 判断是否为算术符号
*
* @param c
* @return
*/
private Boolean isOperator(char c) {
return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')';
}

/**
* 利用ASCII码-40做下标去算术符号优先级
*
* @param cur
* @param peek
* @return
*/
public Boolean compare(char cur, char peek) {
// 如果是peek优先级高于cur,返回true,默认都是peek优先级要低
Boolean result = false;
if (operatPriority[(peek) - 40] >= operatPriority[(cur) - 40]) {
result = true;
}
return result;
}

/**
* 按照给定的算术运算符做计算
*
* @param firstValue
* @param secondValue
* @param currentOp
* @return
*/
private String calculate(String firstValue, String secondValue, char currentOp) {
String result = "";
switch (currentOp) {
case '+':
result = String.valueOf(BaseMethod.add(firstValue, secondValue));
break;
case '-':
result = String.valueOf(BaseMethod.sub(firstValue, secondValue));
break;
case '*':
result = String.valueOf(BaseMethod.mul(firstValue, secondValue));
break;
case '/':
result = String.valueOf(BaseMethod.div(firstValue, secondValue));
break;
}
return result;
}
}

spring-BeanDefinition

发表于 2022-05-12

官网springframework 5.3.20 API

BeanDefinition

概述

A BeanDefinition describes a bean instance, which has property values, constructor argument values, and further information supplied by concrete implementations.
This is just a minimal interface: The main intention is to allow a BeanFactoryPostProcessor to introspect and modify property values and other bean metadata.

BeanDefinition描述一个bean实例,该实例具有属性值、构造函数参数值以及具体实现提供的进一步信息。

这只是一个最小的接口:主要目的是允许BeanFactoryPostProcessor内省和修改属性值和其他bean元数据。

方法

setBeanClassName

Specify the bean class name of this bean definition.

The class name can be modified during bean factory post-processing, typically replacing the original class name with a parsed variant of it.

用于指定bean的类型

setScope

Override the target scope of this bean, specifying a new scope name.

更改bean的作用域

isLazyInit

Return whether this bean should be lazily initialized, i.e. not eagerly instantiated on startup. Only applicable to a singleton bean.

返回这个bean是否延迟初始化。

setDependsOn

Set the names of the beans that this bean depends on being initialized. The bean factory will guarantee that these beans get initialized first.

设置此bean依赖于初始化的bean的名称。bean工厂将保证这些bean首先得到初始化。

isPrimary

Return whether this bean is a primary autowire candidate.

返回此bean是否为主要autowire候选。

setInitMethodName

Set the name of the initializer method.

设置初始化方法名称。

  • spring
    • Bean Definition

pyqt5_signals_slots

发表于 2022-01-07

目标

本片博客目标是为了学习和理解,pyqt5 中的事件、信号。

概念

事件(event)

所有的GUI程序都是事件驱动的。事件主要由用户触发,但也可能有其他触发方式:例如网络连接、window manager或定时器。当我们调用QApplication的exec_()方法时会使程序进入主循环。主循环会获取并分发事件。

在事件模型中,有三个参与者:

  • 事件源
  • 事件对象
  • 事件接收者

事件源是状态发生变化的对象。它会生成事件。事件(对象)封装了事件源中状态的变动。事件接收者是要通知的对象。事件源对象将事件处理的工作交给事件接收者。

举例:

一个webfrom表的提交操作,需要经过点击提交按钮->触发click事件->并执行此事件。其中按钮就是事件接收者,onclick方法是事件源,onclick指向的方法是事件对象。

信号&槽

PyQt5有一个独特的signal&slot(信号槽)机制来处理事件。信号槽用于对象间的通信。signal在某一特定事件发生时被触发,slot可以是任何callable对象。当signal触发时会调用与之相连的slot。

实践

案例1(signals&slots-helloword)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# -*- coding: utf-8 -*-

import sys
from PyQt5.QtWidgets import QMainWindow, QPushButton, QApplication


class Example(QMainWindow):

def __init__(self):
super().__init__()

self.initUI()


def initUI(self):

btn1 = QPushButton("Button 1", self)
btn1.move(30, 50)

btn2 = QPushButton("Button 2", self)
btn2.move(150, 50)

btn1.clicked.connect(self.buttonClicked)
btn2.clicked.connect(self.buttonClicked)

self.statusBar()

self.setGeometry(300, 300, 290, 150)
self.setWindowTitle('Event sender')
self.show()


def buttonClicked(self):

sender = self.sender()
self.statusBar().showMessage(sender.text() + ' was pressed')


if __name__ == '__main__':

app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

其中 btn1.clicked.connect(self.buttonClicked) 中的self.buttonClicked就是槽中插入的信号

案例2(自定义-signals)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtCore import pyqtSignal, QObject
from PyQt5.QtWidgets import QMainWindow, QApplication


class Communicate(QObject):

closeApp = pyqtSignal()


class Example(QMainWindow):

def __init__(self):
super().__init__()

self.initUI()


def initUI(self):

self.c = Communicate()
self.c.closeApp.connect(self.close)

self.setGeometry(300, 300, 290, 150)
self.setWindowTitle('Emit signal')
self.show()


def mousePressEvent(self, event):

self.c.closeApp.emit()


if __name__ == '__main__':

app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

其中Communicate().closeApp为自定义信号

总结

事件

pyqt5 中的事件源用来生成事件、事件对象用于封装事件源、事件接收者就是要使用事件的对象。

信号槽

信号signals用于描述个人通过事件要做的一些事情。

槽slots用于将信号和事件绑定在一起。

raspberry4B搭建集群实战

发表于 2021-12-11 | 更新于 2021-12-12

集群的规划

如今的时代显然已经跨域20世纪的互联网时代跨入了物联网大数据的时代。为了能够紧跟时代的步伐个人决定学习大数据、云原生等新技术。说到这些技术都必须基于Paas 平台的支撑。个人之前使用过阿里云、华为云等需要支付一定的资金。为了节省开支和能够更深层次的了解分部署计算应用的整体结构,所以我决定使用raspberry来模拟计算机集群,搭建一个属于自己的微集群。

基于上面的考虑本次集群的规划从以下2个方面来考虑

1.经济方面

2.实用方面

集群物理图

搭建集群

master主控安装

系统的烧录

安装docker

设置apt-repostory

1
2


docker-ce=5:20.10.7~3-0~debian-bullseye

docker-ce-cli=5:20.10.7~3-0~debian-bullseye

containerd.io=1.4.6-1

1
apt-get install -y docker-ce=5:20.10.7~3-0~debian-bullseye docker-ce-cli=5:20.10.7~3-0~debian-bullseye containerd.io=1.4.6-1

系统的一些基础配置

kubectl、kubelet、kubeadm 安装

kuberentes 引导式安装集群

初始化主节点

1
2
3
4
5
6
7
8
9
10
11
#所有机器添加master域名映射,以下需要修改为自己的
echo "192.168.1.110 cluster-endpoint" >> /etc/hosts

#主节点初始化
kubeadm init \
--apiserver-advertise-address=192.168.1.110 \
--control-plane-endpoint=cluster-endpoint \
--image-repository k8simage \
--kubernetes-version v1.20.9 \
--service-cidr=10.96.0.0/16 \
--pod-network-cidr=172.31.0.0/16

[ERROR SystemVerification]: missing required cgroups: memory 问题

这个问题一般是由树莓派的兼容性和相关配置错误引起的 Cgroup 问题。

解决方案

1
2
3
4
5
$ vi /boot/cmdline.txt

net.ifnames=0 dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=LABEL=writable rootfstype=ext4 elevator=deadline cgroup_enable=memory cgroup_memory=1 rootwait fixrtc

$ reboot

[ERROR Swap]: running with swap on is not supported. Please disable swap

Swap 分区在开启状态下无法进行 kubeadm init。

解决方案

1
2
$ swapoff -a
$ free -m

节点安装

docker

  1. set apt-get repository
1
2
3
4
5
6
sudo apt-get update
sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release
  1. add docker official GPG key

    1
    curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
  2. 设置apt稳定版本库

    1
    2
    3
    4
    5
    echo \
    "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
    $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

    sudo apt-get update
  3. install docker-ce docker-ce-cli containerd.io

    1
    apt-get install -y docker-ce=5:20.10.7~3-0~debian-bullseye docker-ce-cli=5:20.10.7~3-0~debian-bullseye containerd.io=1.4.6-1
  4. 设置加速私服、docker 开机启动

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    sudo mkdir -p /etc/docker
    sudo tee /etc/docker/daemon.json <<-'EOF'
    {
    "registry-mirrors": ["https://82m9ar63.mirror.aliyuncs.com"],
    "exec-opts": ["native.cgroupdriver=systemd"],
    "log-driver": "json-file",
    "log-opts": {
    "max-size": "100m"
    },
    "storage-driver": "overlay2"
    }
    EOF
    systemctl enable docker --now
    sudo systemctl daemon-reload
    sudo systemctl restart docker

系统基础配置

1
2
3
4
5
6
7
8
9
10
11
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF

cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sudo sysctl --system

echo "192.168.1.110 cluster-endpoint" >> /etc/hosts

kubelet、kubeadm 安装

1
2
3
apt-get install -y kubectl=1.20.9-00 kubelet=1.20.9-00 kubeadm=1.20.9-00

systemctl enable kubelet --now

kubeadm init

1
2
3
swapoff -a
echo "cgroup_enable=memory cgroup_memory=1" >> /boot/cmdline.txt
reboot

join master

vim json格式化工具

capture_20211212191335313

12…7
WenLiangBao

WenLiangBao

个人技术总结。(*^_^*)温故而知新,可以为师矣

62 日志
7 标签
Creative Commons
© 2024 WenLiangBao
由 Hexo 强力驱动 v3.8.0
|
主题 – NexT.Mist v7.0.0