LOGO
首页 网站广场 站长动态 活跃度榜 全部站长 审核查询 逛逛好站 留言交流 提交申请 关于本站

站长动态

站长动态所展示的是已加入好站网成员站长文章
共同步 2747 篇文章
(每2小时更新一次)
阿川
入驻第1年
今天我去钓鱼了
Debug
入驻第1年
Go 语言基础 数组、切片、映射
在 Go 语言中,为便于存储及管理用户数据,其数据结构设计分为数组 Array、切片 Slice、映射 Map 三种结构。 近期又看了 Go 语言基础的内容,看了一下这三种结构实现的原理: 数组 Array 数组是切片和映射的基础数据结构; 数组是长度固定的数据类型并且在内存中也是连续分配的,固索引数组数据速度是非常快的; 声明数组时需要指定数组存储的类型及数量(数组的长度); 数组变量的类型包括数组长度和元素的类型,只有两部分都相同的数组才可相互赋值。 创建及初始化 一旦声明了数组,其本身的数据类型及长度都是不可以进行变更。 1 2 3 4 5 6 7 8 9 // 使用数组字面量声明数组 array := [5]int{1, 2, 3, 4, 5} // 自动推导长度声明数组 array := [...]int{1, 2, 3, 4, 5, 6} // 使用 ... 代替长度,根据初始化元素个数推导 // 声明数组并指定特定元素值 array := [5]int{1:10, 2:20} 指针类型 数组元素的类型可以为任何内置类型,也可以是某种结构类型,也可以是指针类型。 1 2 3 4 5 6 7 // 声明一个元素长度为 3 的指向字符串的指针数组 var array1 [3]*string // 为指针数组指定元素 *array1[0] = "demo0" *array1[1] = "demo1" *array1[2] = "demo2" 多维数组 数组本身是一维数据,多维数组是由多个数组组合而来的。 1 2 3 4 5 6 // 声明一个二维数组 var array = [3][2]int // 声明了一个两个维度为 3 和 2 的元素 // 初始化二维数组 var array = [3][2]int{ {1, 2}, {3, 4}, {5, 6}} 在函数间传递数组:由于在函数间传递变量时,传递的总是变量的值的副本,所以在传递数组变量时将拷贝整个数组!在定义函数时,对于较大的数据类型应该把参数设计为指针类型,这样在调用函数时,只需在栈上分配给每个指针8字节的内存,但这意味着会改变指针指向的值(共享的内存),其实大部分情况下应该使用切片类型,而不是数组。 切片 Slice 切片 slice 是引用类型,它引用了其指针字段所指向的底层数组的一部分或全部; 切片是围绕动态数组的概念构建的; 切片的动态增长是通过 append 来实现的; 缩小则是通过对它再次切片来实现,通过再次切片获得的新切片将和原切片共享底层数组,它们的指针指向同一个底层数组。 创建及初始化 切片类型有3个字段: 指针:指向切片所包含的第一个元素在底层数组中的地址; 长度:切片所包含的底层数组的元素的个数(切片可访问的元素的个数); 容量:切片允许增长到的最大元素个数,即底层数组的长度。 make 和切片字面量 1 2 3 4 5 6 // 使用 make 创建一个切片 slice := make([]int, 3) // 创建一个具有长度和容量的切片 slice := make([]int, 1, 6) // 长度为 1,容量为 6 个元素 nil 和空切片 1 2 3 4 5 6 // nil 字符串切片 var slice []string // 空切片 slice := []int{} // 空的整形切片 由于切片只是引用了底层数组,底层数组的数据并不属于切片本身,所以一个切片只需要 24字节的内存(在 64位机器上):指针字段 8字节、长度字段 8字节、容量字段 8字节。所以在函数之间直接传递切片是高效的,只需分配 24字节的栈内存。 len函数可返还切片的长度、cap函数可返还切片的容量。 映射 Map 映射 map 是用来存储一系列的无序键值对; 映射是无序的集合,其实现使用了散列表; 映射的散列表包含一组桶,每个桶里存储着一部分键值对; 映射内部使用了两个数组: 第一个数组:存储着用于选择桶的散列键的高八位值,该数组用于区分每个键值对要存在哪个桶里; 第二个数组:每个桶里都有一个字节数组,先依次存储了该桶里的所有键,之后存储了该桶的所有值; 创建及初始化 1 2 3 4 5 6 7 8 9 10 11 12 // 创建一个映射 存储学生信息 students := map[string]string{ "name" : "mengxiaoyu", "age" : "22", "sex" : "boy", "hobby": "pingpang", } // 显示映射所有信息 for key, value := range students{ fmt.printf("key:%s, \t value:%s\n", key, value); } 遍历映射的键值对时的顺序是随机,若要有序的获得映射的键值对,则需要先遍历出映射的键存到一个切片中,然后排序该切片,最后遍历该切片,按切片中元素的顺序去映射中取对应的值。 关注微信公众号,第一时间获取最新内容,让我们一起变得更强!Debug客栈:订阅本站· 文章归档· 我的项目· 友情链接· 我的使用· 飞湾计划· 摄影展集· 我的主页
Debug
入驻第1年
Go 语言使用 net 包实现 Socket 网络编程
TCP/IP TCP/IP 传输协议,即传输控制/网络协议,也叫作网络通讯协议。它是在网络的使用中的最基本的通信协议。TCP/IP 传输协议对互联网中各部分进行通信的标准和方法进行了规定。并且,TCP/IP 传输协议是保证网络数据信息及时、完整传输的两个重要的协议。TCP/IP 传输协议是严格来说是一个四层的体系结构,应用层、传输层、网络层和数据链路层都包含其中。 TCP/IP 协议簇常见通信协议 应用层:TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 等等 传输层:TCP,UDP 网络层:IP,ICMP,OSPF,EIGRP,IGMP 数据链路层:SLIP,CSLIP,PPP,MTU Socket 两个进程如果需要进行通讯最基本的一个前提能能够唯一的标示一个进程,在本地进程通讯中我们可以使用 PID 来唯一标示一个进程,但 PID 只在本地唯一,网络中的两个进程 PID 冲突几率很大,这时候我们需要另辟它径了,我们知道 IP 层的 ip 地址可以唯一标示主机,而 TCP 层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用 ip 地址+协议+端口号唯一标示网络中的一个进程。 能够唯一标示网络中的进程后,它们就可以利用 socket 进行通信了,什么是socket 呢?我们经常把 socket 翻译为套接字,socket 是在应用层和传输层之间的一个抽象层,它把 TCP/IP 层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。 socket是一种"打开—读/写—关闭"模式的实现,服务器和客户端各自维护一个"文件",在建立连接打开后,可以向自己文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件。 Socket 是实现“打开–读/写–关闭”这样的模式,以使用 TCP 协议通讯的 socket 为例。如下图所示: TCP 实现 一个 TCP 客户端进行 TCP 通信的流程如下: 建立与服务端的链接 进行数据收发 关闭链接 server 端 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 package main import ( "bufio" "fmt" "net" ) func process(conn net.Conn) { // 处理完关闭连接 defer conn.Close() // 针对当前连接做发送和接受操作 for { reader := bufio.NewReader(conn) var buf [128]byte n, err := reader.Read(buf[:]) if err != nil { fmt.Printf("read from conn failed, err:%v\n", err) break } recv := string(buf[:n]) fmt.Printf("收到的数据:%v\n", recv) // 将接受到的数据返回给客户端 _, err = conn.Write([]byte("ok")) if err != nil { fmt.Printf("write from conn failed, err:%v\n", err) break } } } func main() { // 建立 tcp 服务 listen, err := net.Listen("tcp", "127.0.0.1:9090") if err != nil { fmt.Printf("listen failed, err:%v\n", err) return } for { // 等待客户端建立连接 conn, err := listen.Accept() if err != nil { fmt.Printf("accept failed, err:%v\n", err) continue } // 启动一个单独的 goroutine 去处理连接 go process(conn) } } client 端 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 package main import ( "bufio" "fmt" "net" "os" "strings" ) func main() { // 1、与服务端建立连接 conn, err := net.Dial("tcp", "127.0.0.1:9090") if err != nil { fmt.Printf("conn server failed, err:%v\n", err) return } // 2、使用 conn 连接进行数据的发送和接收 input := bufio.NewReader(os.Stdin) for { s, _ := input.ReadString('\n') s = strings.TrimSpace(s) if strings.ToUpper(s) == "Q" { return } _, err = conn.Write([]byte(s)) if err != nil { fmt.Printf("send failed, err:%v\n", err) return } // 从服务端接收回复消息 var buf [1024]byte n, err := conn.Read(buf[:]) if err != nil { fmt.Printf("read failed:%v\n", err) return } fmt.Printf("收到服务端回复:%v\n", string(buf[:n])) } } UDP 实现 UDP 协议(User Datagram Protocol)中文名称是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联)参考模型中一种无连接的传输层协议,不需要建立连接就能直接进行数据发送和接收,属于不可靠的、没有时序的通信,但是UDP协议的实时性比较好,通常用于视频直播相关领域。 server 端 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 package main import ( "fmt" "net" ) func main() { // 建立 udp 服务器 listen, err := net.ListenUDP("udp", &net.UDPAddr{ IP: net.IPv4(0, 0, 0, 0), Port: 9090, }) if err != nil { fmt.Printf("listen failed error:%v\n", err) return } defer listen.Close() // 使用完关闭服务 for { // 接收数据 var data [1024]byte n, addr, err := listen.ReadFromUDP(data[:]) if err != nil { fmt.Printf("read data error:%v\n", err) return } fmt.Printf("addr:%v\t count:%v\t data:%v\n", addr, n, string(data[:n])) // 发送数据 _, err = listen.WriteToUDP(data[:n], addr) if err != nil { fmt.Printf("send data error:%v\n", err) return } } } client 端 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 package main import ( "fmt" "net" ) func main() { // 建立服务 listen, err := net.DialUDP("udp", nil, &net.UDPAddr{ IP: net.IPv4(0, 0, 0, 0), Port: 9090, }) if err != nil { fmt.Printf("listen udp server error:%v\n", err) } defer listen.Close() // 发送数据 sendData := []byte("Hello server") _, err = listen.Write(sendData) // 发送数据 if err != nil { fmt.Println("发送数据失败,err:", err) return } // 接收数据 data := make([]byte, 4096) n, remoteAddr, err := listen.ReadFromUDP(data) // 接收数据 if err != nil { fmt.Println("接收数据失败,err:", err) return } fmt.Printf("recv:%v addr:%v count:%v\n", string(data[:n]), remoteAddr, n) } 参考文章 Go语言基础之网络编程 - 李文周的个人博客 简单理解Socket - 谦行 - 博客园 TCP/IP协议 - 百度百科 详解TCP连接的“三次握手”与“四次挥手”(下) 关注微信公众号,第一时间获取最新内容,让我们一起变得更强!Debug客栈:订阅本站· 文章归档· 我的项目· 友情链接· 我的使用· 飞湾计划· 摄影展集· 我的主页
Debug
入驻第1年
Linux Vim 命令手记
经常使用 Linux 的同学在编辑文本文件的时候一定知道 Vim 这一款神器,它代替 Linux 默认原装的 Vi 编辑器,它的快捷键可以使你在操控文件的时候如庖丁解牛般流畅,博主目前只会简单的命令,感觉不能满足开发需求,今天特地的学习了一下,并且针对于常用的命令做了整理及汇总: 开源项目 首先,Vim 编辑器是一个开源的项目,按照惯例,请给开发者一个 Star 奖励: https://github.com/vim/vim 常用命令示意图 常用命令参考 快捷键 操作说明 Ctrl + f 屏幕向下移动一页,类似 Page Down 按键 Ctrl + b 屏幕向上移动一页,类似 Page Up 按键 0 或 Home 键 移动到这一行最前面的字符处 $ 或 End 键 移动到这一行最后面的字符处 G 移动到这个文件的最后一行 gg 移动到这个文件的第一行,相当于 1G N[Enter] N 为数字。光标向下移动 N 行 /word 向下寻找一个名称为 word 的字符串 ?word 向上寻找一个名称为 word 的字符串 n 搭配查找 word 字符串使用,代表重复前一个查找的操作。例:如果前一个命令执行了 /word 命令去向下查找 word 这个字符串,当按下 n 后,会继续向下查找 word 这个字符串。 N 搭配查找 word 字符串使用,代表重复前一个查找的操作(反向)。 :n1,n2s/word1/word2/g 将此文本中的 word1字符串 替换为 word2 字符串 :1,$s/word1/word2/gc 将此文本中的 word1字符串 替换为 word2 字符串【给用户 confim提示】 x, X 在一行字符中,x为向后删除一个字符,X为向前删除一个字符 dd 删除光标所在那一行 ndd n为数字,删除光标所在向下n行 yy 复制光标所在那一行 nyy n为数字,复制光标所在向下n行 p, P p将已经复制的数据在光标下一行粘贴 P将已经复制的数据在光标上一行粘贴 u 复原前一个操作 Ctrl + r 重做上一个操作 . 重复上一个操作 模式切换 快捷键 操作说明 i, I 进入插入模式(Insert mode): i为目前光标所在处插入,I为在目前行所在的第一个非空格符处插入。 a, A 进入插入模式(Insert mode): a为目前光标的下一个字符处插入,A为在目前行所在的最后一个字符处开始插入。 o,O 进入插入模式(Insert mode): o为在目前光标所在下一行插入一个新行,O为在目前光标所在上一行插入一个新行。 r,R 进入替换模式(Replace mode):r 只会替换光标所在的那一个字符一次,R 会替换光标所在的文字,直到按下 [esc] 键。 [esc] 退出编辑模式 基础操作 快捷键 操作说明 快捷键 操作说明 :w 将编辑的文件写入磁盘文件中去。 :q! 强制退出编辑,且不保存操作。 :q 退出编辑,进入到命令行模式中去。 :wq 保存且退出编辑。 :wq! 强制保存且退出编辑。 Vim 环境修改。 :set nu 显示行号,设置后会在没有行前面前缀对应行号。 :set nonu 与:set nu相反,取消行号显示 键盘标识 关注微信公众号,第一时间获取最新内容,让我们一起变得更强!Debug客栈:订阅本站· 文章归档· 我的项目· 友情链接· 我的使用· 飞湾计划· 摄影展集· 我的主页
Debug
入驻第1年
怎么优雅的选择 MySQL 存储引擎
对于数据库这一块询问比较多的就是在 MySQL 中怎么去选择一种合适当前业务需求的存储引擎,而 MySQL 中支持的存储引擎又有很多种,那么 MySQL 中分别又有那些,怎么优雅的使用呢? 划分引擎原因 在文件系统中,MySQL 将每个数据库(也可以称之为 schema )保存为数据目录下的一个子目录。创建表时,MySQL 会在数据库子目录下创建一个和表同名的 .frm 文件保存表的定义。例如创建一个名为 DebugTable 的表,MySQL 会在 DebugTable.frm 文件中保存该表的定义。 因为 MySQL 使用文件系统的目录和文件来保存数据库和表的定义,大小写敏感性和具体的平台密切相关。在 Windows 系统中,大小写是不敏感的;而在类 Unix 系统中则是敏感的。不同的存储引擎保存数据和索引的方式是不同的,但表的定义则是在 MySQL 服务层wk统一处理的。 查看支持引擎 想了解 MySQL 中支持的引擎的情况,可以使用如下命令查看: 1 show engines; 结果如下(MySQL版本:Ver 8.0.19): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 mysql> show engines; +--------------------+---------+----------------------------------------------------------------+--------------+------+------------+ | Engine | Support | Comment | Transactions | XA | Savepoints | +--------------------+---------+----------------------------------------------------------------+--------------+------+------------+ | FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL | | MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO | | InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES | | PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO | | MyISAM | YES | MyISAM storage engine | NO | NO | NO | | MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO | | BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO | | CSV | YES | CSV storage engine | NO | NO | NO | | ARCHIVE | YES | Archive storage engine | NO | NO | NO | +--------------------+---------+----------------------------------------------------------------+--------------+------+------------+ 9 rows in set (0.00 sec) 存储引擎分类 MySQL 存储引擎分类有 MyISAM、InnoDB、Memory、Merge等,可以看上面表中列出的支持引擎,但是其中最为常用的就是 MyISAM 和 InnoDB 两个引擎,其中针对于以上讲到的存储引擎,如下表进行对比: 对比项目 MyISAM InnoDB Memory Merge 存储限制 256TB 64TB RAM 内存表 / 是否支持事务 否 是 否 否 是否支持全文索引 是 否 否 否 是否支持数索引 是 是 是 否 是否支持哈希索引 否 否 是 否 是否支持数据缓存 否 是 否 否 是否支持外键索引 否 是 否 否 备注 支持事务,行级锁定和外键 指向MyISAM表操作 MyISAM 与 InnoDB 区别 两种类型最主要的差别是InnoDB支持事务处理与外键和行级锁。 InnoDB 可借由事务日志( Transaction Log )来恢复程序崩溃( crash ),或非预期结束所造成的数据错误; 而 MyISAM 遇到错误,必须完整扫描后才能重建索引,或修正未写入硬盘的错误。 InnoDB 的修复时间,一般都是固定的,但 MyISAM 的修复时间,则与数据量的多寡成正比。 相对而言,随着数据量的增加,InnoDB 会有较佳的稳定性。 MyISAM 必须依靠操作系统来管理读取与写入的缓存,而 InnoDB 则是有自己的读写缓存管理机制。( InnoDB 不会将被修改的数据页立即交给操作系统)因此在某些情况下,InnoDB 的数据访问会比 MyISAM 更有效率。 InnoDB 目前并不支持 MyISAM 所提供的压缩与 terse row formats(简洁的行格式) ,所以对硬盘与高速缓存的使用量较大。 当操作完全兼容 ACID(事务)时,虽然 InnoDB 会自动合并数笔连接,但每次有事务产生时,仍至少须写入硬盘一次,因此对于某些硬盘或磁盘阵列,会造成每秒 200 次的事务处理上限。 若希望达到更高的性能且保持事务的完整性,就必使用磁盘缓存与电池备援。 当然 InnoDB 也提供数种对性能冲击较低的模式,但相对的也会降低事务的完整性。而MyISAM则无此问题,但这并非因为它比较先进,这只是因为它不支持事务。 应用场景 MyISAM 管理非事务表。它提供高速存储和检索,以及全文搜索能力。如果应用中需要执行大量的 SELECT 查询,那么 MyISAM 是更好的选择。 InnoDB 用于事务处理应用程序,具有众多特性,包括 ACID 事务支持。如果应用中需要执行大量的 INSERT 或 UPDATE 操作,则应该使用 InnoDB,这样可以提高多用户并发操作的性能。 参考文章 Mysql 存储引擎的区别和比较 - zgrgfr - CSDN Mysql的存储引擎之:MERGE 存储引擎 - 翔之天空 - CSDN MySQL存储引擎之 Merge 引擎 MySQL存储引擎 - MyISAM与InnoDB区别 - Rocky - 知乎 MySQL引擎介绍 - 慕课网 - 知乎 关注微信公众号,第一时间获取最新内容,让我们一起变得更强!Debug客栈:订阅本站· 文章归档· 我的项目· 友情链接· 我的使用· 飞湾计划· 摄影展集· 我的主页
阿川
入驻第1年
JetBrains 官方推中文简体包了
Holley
入驻第1年
脑洞《我不是完整的我》世界也是虚拟般的存在 有与我一样经历吗?
经常在出现在梦中各种情形,有古代、有未来、异界等场景,这些场景的出现是为什么? 经常出现正在做着一件事,还没做完就灵光一闪马上知道结果,这又是为什么?
阿川
入驻第1年
ThinkPHP 6.0 下载安装与配置
阿川
入驻第1年
Manjaro KDE 调教日记
阿川
入驻第1年
(转)谈 Linux,Windows 和 Mac
Debug
入驻第1年
搭建流媒体服务器 PingOS 平台搭建
近期由于工作原因需要更换公司原有 RTMP 协议推流,由于 Flash 插件今年年底就淘汰使用,并且一直在寻找一种并发好、延时低、同时便于回放功能的应用,在网上找到了基于Nginx + FFmpeg 推流的解决方案,可以实现 HLS 协议推流,看项目介绍可以实现 HLS+ 协议,这个工具安装比较便捷。 首先介绍一下这个开源的项目,欢迎给他们 star,谢谢。 https://github.com/pingostack/pingos 官网地址:https://pingos.io/ 安装 项目文档:https://pingos.io/docs/zh/quick-start 在官方网站的项目文档中讲解的不是很清晰,特别是针对新手来说是有一定的难度,我这里使用的是 Linux CentOS 7.4 64位环境,需要提前安装 Git 应用,这个就不详细讲解了,接下来讲一下如何安装: 1 下载源码 1 git clone https://github.com/pingostack/pingos.git 2 快速安装 1 2 cd pingos ./release.sh -i 3 启动服务 1 2 cd /usr/local/pingos/ ./sbin/nginx 配置 一般情况下,安装完毕 PingOS 后就可以使用了,通过配置文件可以看到 nginx 占用端口为80,rtmp 端口占用为1935 。 但是在实际情况下,80 端口一般是使用于 HTTP 等服务,所以说尽量将服务端口设置为非 80 端口,由于使用了阿里云,可以关闭防火墙,同时配置安全组策略将 8080 入端口设置为允许状态。 下面是修改好的配置文件,位置为:/usr/local/pingos/conf/nginx.conf: 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 user root; daemon on; master_process on; worker_processes 1; #worker_rlimit 4g; #error_log logs/error.log; #error_log logs/error.log notice; error_log logs/error.log info; worker_rlimit_nofile 102400; worker_rlimit_core 2G; working_directory /tmp; #pid logs/nginx.pid; events { # use epoll; worker_connections 1024; multi_listen unix:/tmp/http 8080; multi_listen unix:/tmp/rtmp 1935; } stream_zone buckets=1024 streams=4096; rtmp { log_format log_bandwidth '{"app":"$app","name":"$name","bitrate":$bitrate,"args":"$args","timestamp":$ntp,"ts":"$time_local","type":"$command","remote_addr":"$remote_addr","domain":"$domain"}'; access_log logs/bandwidth.log log_bandwidth trunc=60s; server { listen 1935; serverid 000; out_queue 2048; server_name localhost; application live { rtmp_auto_pull on; rtmp_auto_pull_port unix:/tmp/rtmp; # live_record on; # live_record_path /tmp/record; # recorder r1{ # record all; # record_path /tmp/record; # } # exec_publish bash -c "ffmepg -i rtmp://127.0.0.1/live/$name -c copy /tmp/mp4/$name-$starttime.mp4"; live on; hls on; hls_path /tmp/hls; hls_fragment 4000ms; # hls_max_fragment 6000ms; hls_playlist_length 12000ms; hls2memory on; mpegts_cache_time 20s; hls2_fragment 1300ms; hls2_max_fragment 1600ms; hls2_playlist_length 3900ms; wait_key on; wait_video on; cache_time 3s; low_latency off; fix_timestamp 2s; # h265 codecid, default 12 hevc_codecid 12; } } } http { include mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_X-Forwarded-For" "$http_X-Real-IP" "$host"'; access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #reset_server_name www.test1.com www.test2.com; #gzip on; server { listen 8080; location /rtmp_stat { rtmp_stat all; rtmp_stat_stylesheet /stat.xsl; } location /xstat { rtmp_stat all; } location /sys_stat { sys_stat; } location /control { rtmp_control all; } location /live { flv_live 1935; add_header 'Access-Control-Allow-Origin' '*'; add_header Cache-Control no-cache; } location /ts { ts_live 1935 app=live; } location /hls { # Serve HLS fragments types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } root /tmp; add_header Cache-Control no-cache; add_header 'Access-Control-Allow-Origin' '*'; } location /hls2 { hls2_live 1935 app=live; add_header 'Access-Control-Allow-Origin' '*'; add_header Cache-Control no-cache; } location / { chunked_transfer_encoding on; root html/; } } } 修改完配置之后需要进行 nginx 服务重新载入等操作。 命令 1 2 3 4 5 6 7 8 9 10 11 # 进入到 PingOS 应用目录,下面所有操作皆以此目录下进行 cd /usr/local/pingos/ # 开启 nginx 服务器 ./sbin/nginx # 检查 nginx 配置语法是否正确 ./sbin/nginx -t # 重新加载 nginx 配置 ./sbin/nginx -s reload # 停止 nginx 服务器 ./sbin/nginx -s stop 推流 配置好服务器,可以看一下流媒体服务器推流效果,这里我是用的是 OBS 推流应用,推流端使用的是 RTMP 协议,在播放端使用的是 hls+ 协议。 这里给大家提供两个官方推荐查看推流效果的地址,也是应用提供的 Web 页面: http://ip地址:端口/h5player/flv 无插件播放http-flv直播流 http://ip地址:端口/rtmp_stat 查看当前服务器推流统计数据 播放地址:http://ip地址:端口/hls2/流名.m3u8 参考 PingOS 项目参考 怎么搭建hls低延时直播(lowlatency hls)- 知乎 最后,这是一个系列的文章,后续还有针对 PingOS 流媒体服务还有对应优化,敬请关注 关注微信公众号,第一时间获取最新内容,让我们一起变得更强!Debug客栈:订阅本站· 文章归档· 我的项目· 友情链接· 我的使用· 飞湾计划· 摄影展集· 我的主页
Debug
入驻第1年
数据结构 浅谈归并排序
在 v2ex 社区看到有人提问怎么把十万个电话号码排出出现次数最多的十个电话号码,我看到这个问题的时候第一时间想到的是将十万个电话号码读出来放到 Redis 中,之后做一个动态计数器,使用 foreach 函数对这个电话号码进行遍历,以电话号码为索引 key,计数器 value 进行自增,最后求出最多的电话号码,这样最后时间复杂度为 O(n),不是一个好的解决方案,之后我看到评论区,有人提出使用归并排序,原理是一样的,不过可以将十万个电话号码平均分成十组,之后每组查找电话号码最多的十个号码,最后将十组最多的号码取出来再次进行相加排序,最后得到的最多的十个号码就是十万个电话号码中出现次数最多的号码。 看到这个问题,我不由得想到了我刚来去某浪面试的时候,面试官问我的问题和这个问题基本一致,不过是数的基数比较大,当时的我解决方案和现在我想的一样,很遗憾,没有结果,不得不说技术还是太菜了。之后我查了一下归并排序是采用的分治法的思想,即将一个问题分为若干个小的子问题进行解决,最后问题的解就是子问题结果的解的合并,接下来就详细的了解一下归并排序吧! 基本思想 归并排序 mergesort,是创建在归并操作上的一种有效的排序算法,效率为O(nlogn)。1945年由约翰·冯·诺伊曼首次提出。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。 采用分治思想,将一个问题拆分为若干个问题,之后将若干个问题解决,最后将若干个结果进行合并,即最终结果。 分治合并 在合并结果阶段,可以看到两个子结果的求解数组为[1, 2, 6] 和 [3, 4, 5],将子数组合并排序为 [1, 2, 3, 4, 5, 6]。 算法实现 在这里使用的是 PHP,其实算法思想一致,用啥语言都可以实现,不过一种语言有一种语言的语法 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 <?php class MergeSort { /** * 初始化函数 * MergeSort constructor. * @param array $arr */ public function __construct(array $arr) { // 设置初始数组,左侧下标,及数组总下标大小 $this->mSort($arr, 0, count($arr) - 1); print_r($arr); } /** * 递归拆分数组 * @param array $arr 原始数组 * @param int $left 左侧索引下标 * @param int $right 右侧索引下标 */ public function mSort(array &$arr, int $left, int $right) { if ($left < $right) { $center = floor(($left + $right) / 2); $this->mSort($arr, $left, $center); $this->mSort($arr, $center + 1, $right); $this->mergeArray($arr, $left, $right, $center); } } /** * 合并数组 * @param array $arr * @param int $left * @param int $right * @param int $center */ public function mergeArray(array &$arr, int $left, int $right, int $center) { echo 'sort before:' . $left . ' - ' . $center . ' - ' . $right . ' - ' . implode(',', $arr) . "\n"; $left_i = $left; $right_i = $center + 1; $temp = []; while ($left_i <= $center && $right_i <= $right) { // 当数组A和数组B都没有越界时 if ($arr[$left_i] < $arr[$right_i]) { $temp[] = $arr[$left_i++]; } else { $temp[] = $arr[$right_i++]; } } // 判断 数组A内的元素是否都用完了,没有的话将其全部插入到 temp 数组内: while ($left_i <= $center) { $temp[] = $arr[$left_i++]; } // 判断 数组B内的元素是否都用完了,没有的话将其全部插入到 temp 数组内: while ($right_i <= $right) { $temp[] = $arr[$right_i++]; } // 将 $arr 内排序好的部分,写入到 $arr 内: for ($i = 0, $len = count($temp); $i < $len; $i++) { $arr[$left + $i] = $temp[$i]; } echo 'sort after :' . $left . ' - ' . $center . ' - ' . $right . ' - ' . implode(',', $arr) . "\n"; } } $arr = [2, 1, 6, 3, 5, 4]; new MergeSort($arr); 输出结果: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 sort before:0 - 0 - 1 - 2,1,6,3,5,4 sort after :0 - 0 - 1 - 1,2,6,3,5,4 sort before:0 - 1 - 2 - 1,2,6,3,5,4 sort after :0 - 1 - 2 - 1,2,6,3,5,4 sort before:3 - 3 - 4 - 1,2,6,3,5,4 sort after :3 - 3 - 4 - 1,2,6,3,5,4 sort before:3 - 4 - 5 - 1,2,6,3,5,4 sort after :3 - 4 - 5 - 1,2,6,3,4,5 sort before:0 - 2 - 5 - 1,2,6,3,4,5 sort after :0 - 2 - 5 - 1,2,3,4,5,6 Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5 [5] => 6 ) 结论 归并排序比较占用内存,但却是一种效率高且稳定的算法。归并排序的最好,最坏,平均时间复杂度均为O(nlogn)。 参考文章 图解排序算法(四)之归并排序 - 博客园 归并排序 - 维基百科,自由的百科全书 关注微信公众号,第一时间获取最新内容,让我们一起变得更强!Debug客栈:订阅本站· 文章归档· 我的项目· 友情链接· 我的使用· 飞湾计划· 摄影展集· 我的主页
Debug
入驻第1年
记一次不太正规的装机实践
早就想着装一台组装机,来实操一下高中学的计算机组装与维修 ?,哈哈,开玩笑,想着组装一台电脑是我早有打算的事情,凭借着在学校实验室的时候帮助老师修理百十来台电脑的经验也可以轻松应对,正好家里人有装电脑的需求,本想着装机是一件比较愉快的事情,实时是激动的心、残废的手,装机翻车了,不过整体流程还可以,最后也正常的运行了起来,听我细细道来吧。 配置 朋友出价,我出配置,4000左右机型,性能还可以。 配件名称 型号 价格 CPU 英特尔(Intel)i5 9400F 酷睿六核 盒装CPU处理器 ¥1199 主板 技嘉(GIGABYTE)B365 M AORUS ELITE ¥669 显卡 七彩虹(Colorful)iGame GeForce GTX 1650 SUPER AD Special OC 4G 1530-1755MHz ¥1279 内存条 金士顿(Kingston) DDR4 2666 8GB 台式机内存条 骇客神条 Fury雷电系列 ¥359 SSD 东芝(TOSHIBA)250G SSD固态硬盘 M.2接口(NVME协议) RC500系列 ¥409 电源 鑫谷(Segotep)额定350W 核动力-巡洋舰 Q5 电源 ¥139 散热器 酷冷至尊(Cooler Master) 暴雪T400i 风冷散热器 ¥89.9 机箱 爱国者(aigo)炫影黑京东专供版 电脑机箱(配3把发光风扇/支持ATX主板/蜂窝玻璃面板/背线) ¥229 总价 ¥4322.90 包装 不得不说,京东快递就是很快,不过,快归快,3000米,抱着这三个大箱子往住的地方跑,最后手抖不停???,看来要健身减肥了。 打开了纸箱,买的配件都显露了出来,在床上摆拍了一下。 很壮观,也很有气势,哈哈,接下来就进行拆解组装了………… 组装 一般组装都讲究顺序,作为从不看产品使用说明的我,上来就装起了主板 ?,看到 CPU 和散热风扇在孤零零的躺着,emmm,拆出来吧,唉,就这样才把 CPU 放上,装上了内存,固态 SSD,和散热器,由于太过锋利,又没有防护措施,唉,挂了彩。 此处省略弱鸡的我装机,省略500子,最后终于安装成功。 给大家一个实践得来的建议,装机顺序,一定要记好: 安装 CPU 及散热风扇; 安装内存条、M.2 接口类型的固态; 安装主板,固定扩展插槽位置对齐; 安装电源; 安装显卡; 从背部走线,对应主板、CPU供电插槽、显卡供电插槽、音视频,USB2.0/3.0 、散热器供电插槽插上对应的线,同学们,看说明书; 开机,测试安装如何; 可以的话就整理线,用扎带固定好,关上机箱,就可以喽。 经过以上安装步骤,终于安装完毕,请看结果: 插上电源,为我爆灯……………… 正常运行,感觉良好,记下来就要装系统喽。 系统 首当其从,当然是 Windows10 啦,嗯,没错,只有 Windows10 是可以配得上我亲手装的机器,所谓郎才配女貌 ??。从公司让同事帮忙借了一套显示器及无线键鼠,之后又安装了大白菜系统,开始安装。 不得不说,现在的配置安装 windows10 真的很快,并且开关机可以达到5秒内完成,牛掰。 关注微信公众号,第一时间获取最新内容,让我们一起变得更强!Debug客栈:订阅本站· 文章归档· 我的项目· 友情链接· 我的使用· 飞湾计划· 摄影展集· 我的主页
阿川
入驻第1年
(转)为什么犹太人如此优秀?
Debug
入驻第1年
近期理财学习总结
最近在上了一个在线的理财班(微信群实时上课),因为收费比较便宜,自己抱着学到赚到的原则,看看实际情况进行合理安排自己的进阶课程,因为知道这是一个类似公益性质的课程,之后会推荐他们专业课程,所以自己有一定的衡量,接下来对这个理财做一下小结。 之前并没有意思到理财的重要性,主要是因为理财感觉还比较遥远,后来上课之后了解到,十年至今中国的通货膨胀率远远比现在银行存款利率高,也就是说现在的人民币在手中注定着贬值,贬值的速度远远大于自己资金的积累,最后就会变成一颗韭菜,时间会变成一个巨大的收割机,如果不开始理财,自己会变成新一代的韭菜避免不了被割的风险。 “富人思维”是为期12天理财课程培养的重点,主要是让你养成一个好的攒钱投资的习惯,学会利用“钱生钱”,接下来就给大家介绍一下学习的十四条“富人思维”: 关键富人思维 - 第一条 获得经济独立、财务自由的意义是什么? 经济独立、财富自由并不是独善其身,它的本质是让自己、家人变的更好的能力。 【从个人讲】,可以更好的选择自己喜欢的东西、自己喜欢的生活方式、婚姻方式,最终实现踏踏实实靠自己,得来属于自己的精神自由。把经济这个生存的“命脉”交给他人,其实就是把自己选择的权力让给了他人,也把自己生活的主动权让给了他人。 【从家庭讲】,与爱人共同分担家庭的财务重担,应对老人的医疗花销、孩子的教育花销,让家庭关系因为共同的努力获得财富而更美好,而不是因为钱受到冲击而动摇。 一句话总结:提升理财技能,实现财务独立,获得更多自主选择的权力,获得给家人更好的生活的能力。 关键富人思维 - 第二条 月光或者积蓄不多的人,为什么不能等有钱再学习理财? 月光和积蓄不多本质是错误理财思维造成的结果, 【在花钱上】,很多都是坏支出,一心只想买买买,很多东西在冲动消费之后要么用了几次就放置一边,要么后悔自责又在下次陷入到恶性循环,但对于投资自己成长的好支出,却又思前想后。其关键在于,没有好支出、坏支出的思维意识,被欲望牵着走,没有将有限的资金花在刀刃上。 【在攒钱上】,单纯靠工资攒钱是最低效最差的方式,如果只靠工资收入来攒钱,很可能到退休了还没有攒够理财的本金。真正聪明的小伙伴会在获得第一笔工资收入时就开始选择合适的理财工具来积累自己的本金和非工资收入了。 具有富人思维的人,哪怕是现在月光或者积蓄不多,就会从一开始就通过工资和非工资收入两条路径来增加自己的收入。两条腿走路肯定比只靠工资收入一条腿走的更快更远。 一句话总结:提升财富要靠工资和非工资收入【两条腿】走路,绝对不能独腿前行。 关键富人思维 - 第三条 中产家庭为什么不能沉溺在自己的工资收入中? 中产家庭看似收入比较稳定,其实抗风险能力不强,他们有房贷要还,小孩要养,甚至父母还要大量的开销。 【孩子还未成人的家庭】,孩子没有收入,花销逐年增大,这时候如果夫妻中有一人遇到一段时间不能工作的情况,家庭财务整体情况可能会出现较大落差,进而影响生活质量。 【全职宝妈的家庭】,女性负责照顾孩子,没有工资性收入,只有老公一人的收入是家庭收入的主要来源,如果老公遭遇大裁员等意外情况,家庭很可能立即陷入坐吃山空的财务危机中,或者啃老的尴尬境地。 所以中产家庭更需要尽早尽快建立自己的非工资收入体系,【在没发生意外的时候】,可以为家庭提供一份额外的收入,补贴家用;【在发生意外的时候】,能够抵御财务风险,不至于到毫无收入的被动地步。 学习并掌握获得非工资收入的能力,是为自己负责,也是为了家人负责。 一句话总结:中产的【财务安全】来自工资收入和非工资收入的双管齐下,没有充足的非工资收入的中产家庭,谈不上财务真正安全。 关键富人思维 - 第四条 为什么说复利三要素中最容易掌控的是收益率? 复利三要素,本金、时间、收益率。把钱存在保险箱中,复利会发挥反向作用,把钱一口一口吃掉,长期来看1万元每年贬值500元以上。投资开始的越早,时间要素发挥越大,复利的正向作用越早发挥作用。本金大的人,复利作用也比较大,但是投错了地方,本金再大也会亏完。如果本金和时间都不占优势,那么最有效的就是提高年化收益率,而提高年化收益率的关键在于自己的理财能力。 一句话总结:【时间无法改变,越早开始越好;本金依赖生钱资产;收益率源于理财能力,理财能力才是决定复利终值的关键】。 富人关键思维 - 第五条 为什么说投资自己的大脑、学会理财技能也是中产升级之法? 如同经典书籍《富爸爸》中说的,穷人卖时间换钱,其实本质是“卖命”。他们抱怨自己没有钱,其实本质是他们没有认识到投资自己的大脑是最快的脱贫致富之法。 比如一个专家花费一生写了一部巨著,我们花100元买了他的书回来看,其实某种意义上我们是买到了他一生的生命成果,学到了能获得成千上万的收益,这就叫“站在巨人的肩膀上”,贫穷的矮人站在“巨人的肩膀上”也会达到巨人的视野。 但很多人心疼这点投资大脑的钱,所以一直什么都不懂,一直贫穷下去。反之,穷人也能通过投资自己的头脑,学习他人成功的方法,买他人花了很多时间转化的成果,变成自己的东西,快速创造财富,这是最快的脱贫之法。 一句话总结:心疼投资大脑的钱,一直什么都不懂,不是被通货膨胀割韭菜,就是被投资市场割韭菜,一直穷下去。反之学习他人成功的方法,变成自己的技能,是最快的脱贫、升级之法。 关键富人思维 - 第六条 到底什么时候可以开始投资? 为什么有的人买股票必亏,看了几本书,学了几天课就急急忙忙要去股市里了,我们学车还要几个月,投资作为高度专业化、精细化的一个领域,不经过系统的学习就去“尝试”,这和训练了三天、看了几本武侠小说就上战场的士兵有什么区别呢? 士兵进行系统训练是为了保命,投资者进行系统的学习是为了保钱的“命”,反之,学个半瓶水就去投资市场,美其名为“试试”,这样的“试试”不会学到任何教训、经验,只会收获痛苦。那些经过系统训练的人会把那些无知而自以为是的人收割的一滴血不剩。 【这就是投资的真相】,不系统学习就想赚快钱就是送命。当你打算投资一个目标,有系统的分析方法,不再为了涨跌而心惊胆战的时候,这才是投资可以真正开始的时候。 一句话总结:投资第一原则:不懂不要投,懂了安心投,盲目“尝试”无疑送命,系统训练方可真正保住钱“命”。 关键富人思维 - 第七条 为什么月光、负债的人应该拿出一部分资金学习理财技能? 这里的负债主要指的是让自己的财务状况不断恶化的【坏负债】。 月光和负债只是不懂理财的结果,没有理财技能才是月光和负债的原因。很多人一方面不懂投资的骗局,一方面又眼红想赚一下,最终都入了骗局的“坑”,如果提前投资自己的大脑,难道还会犯这样的错误吗?还有很多人,本来钱就不多,贷款买了一堆耗钱资产,要么不断的刷信用卡、花呗、借呗,窟窿越来越大,要么生活拮据,每天人前风光,人后遭殃。 但对于投资自己,提升理财技能的好负债,他们却斤斤计较,错失了复利的好机会,这样的人生活只会越来越难过。 【成长有顺序,生活致富也有顺序】——先投资大脑,掌握理财的技能,然后再去生钱,月光、负债不学习只会越来越穷?? 一句话总结:月光、负债是财务病,病根是缺少理财技能,忽视病因、不治病根,坏支出、坏负债只会越来越严重。 关键富人思维 - 第八条 股票价格大跌能跌出什么? 我们【投资股票正确的方法】可以分为两大步: 第一步:选出内在价值高的好企业 第二步:在好的价格及时买入 这两步是不能颠倒的。 【当股市的价格出现下跌时】,好企业代表的好股票会出现好的买入价格,但是坏企业会跌出让投机者眼红的“陷阱”。如果在选择企业这一步错了,不管是多便宜的价格都徒劳无功,反而损失惨重。 【理性的投资者】对自己无法预测股票价格有自知之明,因为价格的波动总是难以预测的,因此他们将主要精力放在好企业的选择上,当好价格出现的时候果断出手,而后不管是继续跌还是涨,都是任凭风浪起稳坐钓鱼船。他们一般很少看股票,却获得了很高的收益。 一句话总结:股票大跌既有机会也有陷阱,机会的识别需要眼力,机会的把握需要技能,当眼力和技能配不上这个机会的时候,往往会步入陷阱之中。 关键富人思维 - 第九条 很多人炒股都亏,就说股票风险高,到底该怎么看待投资股票这件事? 【投机炒股的人】,不懂就去投,一心想赚一把就走,那么股市就是一个大赌场,都特别想赢钱,但又特别怕输钱,风险自然是非常大 而且还很容易上当受骗,赚了以为是自己本事,亏了又说运气不好,说到底都是自欺欺人。 涨了开心要命,跌了悲伤绝望,被价格的波动带着一天悲喜两重天,说到底还是没有技能让自己内心踏实? 【真正的投资股票】,是关注股票代表的公司的好坏,是看到股票背后的本质,经过严谨的分析得出的结论。 这样的投资,即使短时间的价格波动也能心理踏实,最终能够获得复利带来的长期收益?? 一句话总结:投资股票的正确姿势是靠分析,能选出好股票风险自然就小。赌徒在股市是把身家性命交给市场,不懂就投,肯定要被懂的人收割的。 关键富人思维 - 第十条 为什么工作者、投资者都需要通晓企业分析技能? 并不是创业者 、大老板才需要了解企业。 【投资中】,股票本质是企业,只有把9大要素都分析清楚,才能分析出好企业,才能给企业估值. 【工作中】,干工作的时候要有企业经营的思维,这样才更容易升职加薪。 即便不为升职,干工作的时候也要有企业经营的思维。因为当你站在更高去看自己的工作内容的时候你才能更好的理解自己的工作内容,这样你可以把工作做成老板真正想要的样子。 而那些只盯着自己的岗位的“井底之蛙”,有的时候挨了骂都不知道为什么,因为他缺乏跳出自己的框框看企业的技能,这就是他自己工作干不好的原因。 所以无论投资、工作,都需要通晓企业分析技能。 总结一句话:工作者用企业分析模型看透工作,投资者用企业分析模型看透股票? 关键富人思维 - 第十一条 为什么要自己掌握理财技能才是最可靠的? 很多之前学员都表示跟着自己的家人、朋友投资,当赚了的时候会特别感激对方,但是亏的了时候又怨恨对方不靠谱。其实他们的家人、朋友很多也真的是好心,但是他们没有掌握投资技能,靠着小道消息,本质是投机,赚了是运气好,长期亏损是必然。 理财投资这么重要的事情,如果交给别人,就像把自己的“财富之命”交给了别人,如果遇上的是一个没有扎实理财技能的人,那就对自己的“财富之命”太不负责了。因为缺乏理财技能的人,是根本拿不住好股票的,他们无法分析企业,就无法正确面对价格的波动,最终还是逃不过亏损的命运。 而听信银行经理的话,选择银行理财,长期看收益连通货膨胀的贬值都跑不赢。 特别是【中产家庭】,与其听信他人的小道消息,【最可靠的】还是自己通过学习成为家庭资产理财师,为自己的家人打理财产,创造更多非工资收入,这才是最安全可靠的方法。 【一句话总结】:最重要的本事需要掌握在自己手中,就像企业要把核心竞争力掌握在自己的手中一样,理财——事关自己和家庭的财富之命,只有自己掌握了,才是对自己的负责。 关键富人思维 - 第十二条 我们最应该为孩子留下什么财富? 我们总想为孩子留下一笔钱、一套房等,这并没有错,但我们给孩子留下的最重要财富却不是金钱。因为如果给孩子留下了金钱,但孩子无法对抗通货膨胀的贬值、缺少科学的理财知识,金山也会吃空,最终落得个流离失所的下场,正如我们前面讲到的山西首富之子一样。 【聪明的父母】会选择在孩子很小的时候就开始正确的财商教育,让孩子从小就养成正确的金钱观,从很小的时候就享受理财技能带来的复利,而【这都取决于父母的理财能力】,如果父母对理财一无所知,或者学个半瓶水,看似明白实则跑偏,那么不仅教不好孩子,还会把孩子带到错误的方向 【不要让孩子像我们父辈和自己一样】,那样又要陷入“无知”—“试错”—“损失”的恶性循环之中,耗费大量的时间成本、试错成本,又错失了大量的机会成本,我们走错的路,就不要让孩子再走一遍了。 【总结一句话】:我们最应该留给孩子的财富是可贵的品格和可靠的理财能力,身教重于言教,用我们的行为带动孩子品格的养成,用我们的理财能力让孩子的财商有一个好基础?? 富人关键思维 - 第十三条 掌握收益率高的工具的科学方法是什么? 【方法一】:很多人刚刚知道有一个高收益的工具,恨不得马上就买一个,然后就自我憧憬能赚多少。或者选择去市场中直接尝试,事实证明,他们自己总结的方法时而有效,时而无效,时而自信找到了暴富出路,时而迷茫否定自己、骂社会,我称之为焦虑的“【烧钱尝试法】”。其实他们不仅损失了自己的血汗钱,同时在错误尝试的时间里,也错过了正确买入好目标的机会。 【方法二】:其实最快的方法,绝对不是马上去盲目尝试,莫刀不误砍材工,应该先去学习,在学习中最快的方法,是什么,是看书吗?如果看书能够实现财务自由,那么很多人早就财务自由了,因为看书最大的弊端就是没有反馈,没有人告诉你学的对还是学的错。沉溺在看书中寻求财富自由的人,不能说不努力,但是因为没有老师指点,很多都成了【无效的努力】,最可怕的不是慢,是选错了方向,走错了路,在错误方向上的努力只是巩固错误。 【方法三】:那么最快的学习方法是什么?答案是【巨人同行法】,跟着已经长期成功的投资者学习,巴菲特的老师是投资之神格雷厄姆,我们前天早读课中8岁的投资神童,她的老师是父亲,也是成功投资家。他们都是一边勤奋学习理论,一边在老师的指导下纠正错误,一直走在一条正确的努力之路上。这就是看似缓慢,但实际最快的投资之路。这是一条少有人懂得的路,也是一条少有人走的路,所以真正赚钱的投资者才不多。你打算选哪条路? 总结一句话:站在巨人的肩膀上,在少有人走的投资学习之路上最快成长。 关键富人思维 - 第十四条 有的投机者说自己也赚钱了,那么选择做投资者到底好在哪? 我们投资理财到底是为了什么呢?赚钱,但进一步想,赚钱是不被钱绑架,能有时间做自己想做的事,能和家人快乐的生活。 【不懂就去投的人】,短期内碰上运气了,也能赚到钱,但是他们是怎么度过的呢,每天把大量时间用来盯着大盘,昼夜想着跌了还是涨了,精神总是高度紧张,甚至睡觉都在想明天股票的情况,因为他们选择了“赌博”。历史证明,绝大多数投机者本来最应该乐观开心的两年,到头来却是在焦虑、闹心中度过的,因为他们没有真正的投资判断依据,这就是投机者的生活。 【懂得投资的人】,通过一整套分析方法选出优质的投资目标,算出买入好价格,买入,持有,再算出卖出合理价格,卖出。剩下的时间该干什么干什么,价格跌了,心里知道这是表面的波动,不被其迷惑,拿得住;价格涨了,知道什么时候该卖出,不冲动,赚踏实稳当钱。更厉害的,长期持有,被分红的复利滋润着。这是学习科学方法的自然成果,这也是不学习像苍蝇撞大运的投机者,与踏实学习走正道的投资者的最大差别。 当然,既不投机,也不投资的人都感受不到这些,他们只能感受到钱越来越不值钱,而自己的生活好像越来越紧吧了。 总结一句话:投资者获得的是金钱自由,时间自由,心理自由,投机者就算撞运赚了点,却一直在焦虑与煎熬中。 以上就是十四条富人思维总结来说就是:“不懂不要投,懂了放心投”。 不过目前没有相关的经验,还是一只实习生,不过还要“利其器”,防止以后踩坑。 关注微信公众号,第一时间获取最新内容,让我们一起变得更强!Debug客栈:订阅本站· 文章归档· 我的项目· 友情链接· 我的使用· 飞湾计划· 摄影展集· 我的主页
Debug
入驻第1年
Redis 知识点汇总
1.Redis数据结构有哪些 ? 1 2 String List Hash Set Sorted Set bitmap Geo HyperLogLog Streams 2.Redis相比memcached有哪些优势? memcached 所有的值均是简单的字符串; redis 作为其替代者,支持更为丰富的数据类型; redis 的速度比 memcached 快很多 redis 可以持久化数据。 3.Redis是单线程,如何解决并发请求访问? redis 利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销。 4. Reids6 淘汰策略有哪些? noeviction: 不删除策略, 达到最大内存限制时, 如果需要更多内存, 直接返回错误信息。大多数写命令都会导致占用更多的内存,有极少数会例外。 LRU算法 allkeys-lru:所有key通用; 优先删除最近最少使用(less recently used ,LRU) 的 key。 volatile-lru:只限于设置了expire 的部分; 优先删除最近最少使用(less recently used ,LRU) 的 key。 随机淘汰 allkeys-random: 所有key通用; 随机删除一部分 key。 volatile-random: 只限于设置了 expire 的部分; 随机删除一部分 key。 volatile-ttl: 只限于设置了expire 的部分; 优先删除剩余时间(time to live,TTL) 短的key。 5.Redis持久化方案有哪些? RDB(Redis DataBase)持久化:是指用数据集快照的方式半持久化模式,记录redis数据库的所有键值对,在某个时间点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,达到数据恢复; AOF(Append-only file)持久化:是指所有的命令行记录以redis命令请求协议的格式完全持久化存储,保存为aof文件。 RDB和AOF的优缺点 : RDB持久化: 优点:RDB文件紧凑,体积小,网络传输快,适合全量复制;恢复速度比AOF快很多。当然,与AOF相比,RDB最重要的优点之一是对性能的影响相对较小。 缺点:RDB文件的致命缺点在于其数据快照的持久化方式决定了必然做不到实时持久化,而在数据越来越重要的今天,数据的大量丢失很多时候是无法接受的,因此AOF持久化成为主流。此外,RDB文件需要满足特定格式,兼容性差(如老版本的Redis不兼容新版本的RDB文件)。 AOF持久化: 与RDB持久化相对应; 优点在于支持秒级持久化、兼容性好; 缺点是文件大、恢复速度慢、对性能影响大。 6.Redis内存划分 数据: 作为数据库,数据是最主要的部分; 这部分占用的内存会统计在used_memory中。 进程本身运行需要的内存: Redis主进程本身运行肯定需要占用内存,如代码、常量池等等; 这部分内存大约几兆,在大多数生产环境中与Redis数据占用的内存相比可以忽略。 这部分内存不是由jemalloc分配,因此不会统计在used_memory中。 缓冲内存: 缓冲内存包括客户端缓冲区、复制积压缓冲区、AOF缓冲区等; 其中,客户端缓冲存储客户端连接的输入输出缓冲;复制积压缓冲用于部分复制功能; AOF缓冲区用于在进行AOF重写时,保存最近的写入命令。 在了解相应功能之前,不需要知道这些缓冲的细节;这部分内存由jemalloc分配, 因此会统计在used_memory中。 内存碎片: 内存碎片是Redis在分配、回收物理内存过程中产生的。 例如,如果对数据的更改频繁,而且数据之间的大小相差很大,可能导致redis释放的空间在物理内存中并没有释放,但redis又无法有效利用,这就形成了内存碎片。内存碎片不会统计在used_memory中。 7.Redis 主从复制 复制是高可用Redis的基础,哨兵和集群都是在复制基础上实现高可用的。 复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。 缺陷:故障恢复无法自动化;写操作无法负载均衡;存储能力受到单机的限制 。 8.Redis哨兵 在复制的基础上,哨兵实现了自动化的故障恢复。 缺陷:写操作无法负载均衡;存储能力受到单机的限制。 9.redis缓存被击穿处理机制 使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个 get缓存方法。 10.缓存和数据库间数据一致性问题 分布式环境下非常容易出现缓存和数据库间的数据一致性问题,针对这一点的话,如果你的项目对缓存的要求是强一致性的,那么请不要使用缓存。 只能采取合适的策略来降低缓存和数据库间数据不一致的概率,而无法保证两者间的强一致性。合适的策略包括合适的缓存更新策略,更新数据库后要及时更新缓存、缓存失败时增加重试机制,例如MQ模式的消息队列 。 11.缓存雪崩问题 像解决缓存穿透一样加锁排队; 建立备份缓存,缓存A和缓存B,A设置超时时间,B不设值超时时间,先从A读缓存,A没有读B,并且更新A缓存和B缓存。 12.Redis分布式 redis支持主从的模式。 原则:Master会将数据同步到slave,而slave不会将数据同步到master。Slave启动时会连接master来同步数据。 这是一个典型的分布式读写分离模型。利用master来插入数据,slave提供检索服务。这样可以有效减少单个机器的并发访问数量 。 13.读写分离模型 通过增加Slave DB的数量,读的性能可以线性增长。为了避免Master DB的单点故障,集群一般都会采用两台Master DB做双机热备,所以整个集群的读和写的可用性都非常高。 读写分离架构的缺陷在于,不管是Master还是Slave,每个节点都必须保存完整的数据,如果在数据量很大的情况下,集群的扩展能力还是受限于单个节点的存储能力,而且对于Write-intensive类型的应用,读写分离架构并不适合。 14.数据分片模型 为解决读写分离模型的缺陷,可以将数据分片模型应用进来。 可以将每个节点看成,都是独立的 master,然后通过业务实现数据分片。 结合上面两种模型,可以将每个 master 设计成由一个 master 和多个slave组成的模型。 15.Redis分布式锁实现 先拿 setnx 来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样? set指令有非常复杂的参数,这个应该是可以同时把setnx和expire合成一条指令来用的! 16.Redis做异步队列 一般使用list结构作为队列,rpush 生产消息,lpop 消费消息。当 lpop 没有消息的时候,要适当sleep一会再重试。 缺点:在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如rabbitmq等。 能不能生产一次消费多次呢?使用pub/sub主题订阅者模式,可以实现1:N的消息队列。 17.Redis中海量数据的正确操作方式 利用SCAN系列命令(SCAN、SSCAN、HSCAN、ZSCAN)完成数据迭代。 18.是否使用过Redis集群,集群的原理是什么? Redis Sentinal着眼于高可用,在master宕机时会自动将slave提升为master,继续提供服务。 Redis Cluster着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。 19.Redis集群方案什么情况下会导致整个集群不可用? 如果有A,B,C三个节点的集群,在没有复制模型的情况下,如果节点B失败了,那么整个集群就会以为缺少5501-11000这个范围的槽而不可用。 20.说说Redis哈希槽的概念 Redis集群没有使用一致性hash,而是引入了哈希槽的概念,Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。 21.Redis集群会有写操作丢失吗?为什么? Redis并不能保证数据的强一致性,这意味这在实际中集群在特定的条件下可能会丢失写操作。 22.怎么测试Redis的连通性? 使用ping命令。 23.怎么理解Redis事务? 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。 24.Redis如何做内存优化? 尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。 比如你的web系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所有信息存储到一张散列表里面。 25.Redis回收进程如何工作的? 一个客户端运行了新的命令,添加了新的数据。Redis检查内存使用情况,如果大于max memory的限制, 则根据设定好的策略进行回收。一个新的命令被执行,等等。所以我们不断地穿越内存限制的边界,通过不断达到边界然后不断地回收回到边界以下。如果一个命令的结果导致大量内存被使用( 例如很大的集合的交集保存到一个新的键),不用多久内存限制就会被这个内存使用量超越。 26.MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据? Redis内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。 27.假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如果将它们全部找出来? 使用keys指令可以扫出指定模式的key列表。如果这个redis正在给线上的业务提供服务,那使用keys指令会有什么问题?会造成阻塞卡顿。 因为redis是单线程的。keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用scan指令,scan指令可以 无阻塞的提取出指定模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys指令长。 28.如果有大量的key需要设置同一时间过期,一般需要注意什么? 如果大量的key过期时间设置的过于集中,到过期的那个时间点,redis可能会出现短暂的卡顿现象。一般需要在时间上加一个随机值,使得过期时间分散一些。 头条面试 1.Redis连接时的 connect 与 pconnect 的区别 connect:脚本结束之后连接就释放了。 pconnect:脚本结束之后连接不释放,连接保持在php-fpm进程中。 2.Redis有哪些结构时间复杂度较高 List 3.Redis hash的实现 哈希对象的编码可以是 ziplist 或者 hashtable 。 ziplist 编码的哈希对象使用压缩列表作为底层实现, 每当有新的键值对要加入到哈希对象时, 程序会先将保存了键的压缩列表节点推入到压缩列表表尾, 然后再将保存了值的压缩列表节点推入到压缩列表表尾, 因此,保存了同一键值对的两个节点总是紧挨在一起, 保存键的节点在前,保存值的节点在后;先添加到哈希对象中的键值对会被放在压缩列表的表头方向, 而后来添加到哈希对象中的键值对会被放在压缩列表的表尾方向。 4.redis 主从同步是怎样的过程? 见第7题 5.redis 的 zset 怎么实现的? 有序集合的编码可以是 ziplist 或者 skiplist 。 ziplist 编码的有序集合对象使用压缩列表作为底层实现, 每个集合元素使用两个紧挨在一起的压缩列表节点来保存, 第一个节点保存元素的成员(member), 而第二个元素则保存元素的分值(score)。 skiplist 编码的有序集合对象使用 zset 结构作为底层实现, 一个 zset 结构同时包含一个字典和一个跳跃表。 小米面试 1.Redis数据结构有哪些 1 String,List,Hash,Set,Sorted Set,bitmap,Geo,HyperLogLog ,Streams 2. Redis 持久化方案有哪些? RDB(Redis DataBase)持久化:是指用数据集快照的方式半持久化模式,记录redis数据库的所有键值对,在某个时间点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,达到数据恢复 AOFAppend-only file。 持久化: 是指所有的命令行记录以redis命令请求协议的格式完全持久化存储)保存为aof文件。 360 面试 1.redis的持久化 RDB(Redis DataBase)持久化: 是指用数据集快照的方式半持久化模式,记录redis数据库的所有键值对,在某个时间点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,达到数据恢复AOFAppend-only file。 持久化: 是指所有的命令行记录以redis命令请求协议的格式完全持久化存储)保存为aof文件。 2.lru算法实现 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 <?php /** * LRU是最近最少使用页面置换算法(Least Recently Used) * 也就是首先淘汰最长时间未被使用的页面 */ class LRU_Cache { private $array_lru = array(); private $max_size = 0; function __construct($size) { // 缓存最大存储 $this->max_size = $size; } public function set_value($key, $value) { // 如果存在,则向队尾移动,先删除,后追加 if (array_key_exists($key, $this->array_lru)) { unset($this->array_lru[$key]); } // 长度检查,超长则删除首元素 if (count($this->array_lru) > $this->max_size) { array_shift($this->array_lru); } // 队尾追加元素 $this->array_lru[$key] = $value; } public function get_value($key) { $ret_value = false; if (array_key_exists($key, $this->array_lru)) { $ret_value = $this->array_lru[$key]; // 移动到队尾 unset($this->array_lru[$key]); $this->array_lru[$key] = $ret_value; } return $ret_value; } public function vardump_cache() { var_dump($this->array_lru); } } $cache = new LRU_Cache(5); $cache->set_value("01", "01"); $cache->set_value("02", "02"); $cache->set_value("03", "03"); $cache->set_value("04", "04"); $cache->set_value("05", "05"); $cache->vardump_cache(); $cache->set_value("06", "06"); $cache->vardump_cache(); $cache->set_value("03", "03"); $cache->vardump_cache(); $cache->set_value("07", "07"); $cache->vardump_cache(); $cache->set_value("01", "01"); $cache->vardump_cache(); 关注微信公众号,第一时间获取最新内容,让我们一起变得更强!Debug客栈:订阅本站· 文章归档· 我的项目· 友情链接· 我的使用· 飞湾计划· 摄影展集· 我的主页
Debug
入驻第1年
Linux >/dev/null 2>&1 命令使用说明
近期在开发项目中遇到了PHP使用shell_exec执行 Shell 命令的问题,具体说是 Shell 使用 FFmpeg 软件进行录制直播流,但是 PHP 等待命令执行时间是有限的,并且会出现等待时间过长导致该执行接口出现未响应问题,寻找了网上方法,发现了一种比较好的方式,就是将要执行的Shell语句后面加上>/dev/null 2>&1这段特殊的命令,简单来说就是将执行的 Shell 操作放到后台进行运行,将快捷反应执行的操作,解决执行 Shell 语句等待问题,接下来就是对这段命令的解析: 命令的结果可以通过%>的形式来定义输出。 /dev/null 代表空设备文件 > 代表重定向到哪里,例如:echo "123" > /home/123.txt; 1 表示 stdout 标准输出,系统默认值是 1,所以>/dev/null等同于1>/dev/null; 2 表示 stderr 标准错误; & 表示等同于的意思,2>&1,表示 2 的输出重定向等同于 1。 针对下面数字的代表含义的解释: 0:表示键盘输入(stdin) 1:表示标准输出(stdout),系统默认是1 2:表示错误输出(stderr) > /dev/null 2>&1 语句含义: > /dev/null : 首先表示标准输出重定向到空设备文件,也就是不输出任何信息到终端,说白了就是不显示任何信息。 2>&1 :接着,标准错误输出重定向(等同于)标准输出,因为之前标准输出已经重定向到了空设备文件,所以标准错误输出也重定向到空设备文件。 关注微信公众号,第一时间获取最新内容,让我们一起变得更强!Debug客栈:订阅本站· 文章归档· 我的项目· 友情链接· 我的使用· 飞湾计划· 摄影展集· 我的主页
Debug
入驻第1年
JavaScript 飞雪特效
马上就要到了传统节日“春节”?,网站添加了飞雪❄️特效,从网上找了源代码,先要感谢张戈博客分享?,现计划将网站在今天上线至过年回来下线,看看可以么,你可以复制到自己的网站或者博客体验一波,加上《一剪梅》真是别有一番滋味。 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 <script type="text/javascript"> (function($){ $.fn.snow = function(options){ var $flake = $('<div id="snowbox" />').css({'position': 'absolute','z-index':'9999', 'top': '-50px'}).html('❄'), documentHeight = $(document).height(), documentWidth = $(document).width(), defaults = { minSize : 6, maxSize : 10, newOn : 1000, flakeColor : "#FFFFFF" /* 此处可以定义雪花颜色 */ }, options = $.extend({}, defaults, options); var interval= setInterval( function(){ var startPositionLeft = Math.random() * documentWidth - 100, startOpacity = 0.5 + Math.random(), sizeFlake = options.minSize + Math.random() * options.maxSize, endPositionTop = documentHeight - 200, endPositionLeft = startPositionLeft - 500 + Math.random() * 500, durationFall = documentHeight * 10 + Math.random() * 5000; $flake.clone().appendTo('body').css({ left: startPositionLeft, opacity: startOpacity, 'font-size': sizeFlake, color: options.flakeColor }).animate({ top: endPositionTop, left: endPositionLeft, opacity: 0.2 },durationFall,'linear',function(){ $(this).remove() }); }, options.newOn); }; })(jQuery); $(function(){ $.fn.snow({ minSize: 5, /* 定义雪花最小尺寸 */ maxSize: 20,/* 定义雪花最大尺寸 */ newOn: 800 /* 定义密集程度,数字越小越密集 */ }); }); </script> 关注微信公众号,第一时间获取最新内容,让我们一起变得更强!Debug客栈:订阅本站· 文章归档· 我的项目· 友情链接· 我的使用· 飞湾计划· 摄影展集· 我的主页
小十
入驻第1年
2019-12-31
时间过得还是挺快的。19年的最后一天。侥幸得到了一天的休息。取了房子合同,领了超市的东西,然后就等着这一天结束。 最近进行了一下人事调整,距离最远,责任也更重。年后去新的运维班。 这也是上班以来的第一次变动。下一次的变动是什么时候,往哪个方向发展,还不能预知。
Debug
入驻第1年
2019 年度总结
2019年,这一年来是我经历最多的一年,上半年的我还在学校上着学校学年安排的课程,谈着美好的校园恋爱,下半年就脱离了校园生活,开始独自一人的北漂生活,这一年来也是这个社会变化较大的一年,5G 的商业化的元年,最难就业的一年,等等,这一年现在告诉自己,我坚持了下来,在这个多变的社会生存了下来,顺利找到了实习工作,从校园实验室生活转变为两点一线的上班生活,开始了不一样的生活体验。 这一年来,我的博客访问量也逐渐增多,网站使用了阿里云 ECS + OSS + CDN 全套服务提升性能,虽然写的文章不及阮一峰老师的千万分之一,但是我可以自豪的说,这一年我坚持了下来,持续的积累技术知识及新型的技术的评价让我的博客文章逐渐的多了起来,在项目中的开发知识积累也都写在博客上面,逐步丰富自己的技术栈,使自己成为一个足够优秀的人,来到北京逐渐发现,自己是那千万人中最最平凡的一类人,正如现在实习公司所说:“平凡人做非凡事,成就非凡人生价值”,不断的提升自己的技术能力及分析问题的能力是我现在要做的,另外也是我2020年博客更新的一大方向,2019年,感谢支持Debug客栈成长的小伙伴们,谢谢你们的鼓励与支持,你也可以加入我的QQ群聊,大话人生 @Debug客栈交流群。 2020年,迎来我大学的结束,并且我也将从实习生的身份转变为应届生,开始了真正的工作,去为社会主义添砖加瓦,2020年加油,奥力给!!! 热门文章 接下来将网站本年度每月阅读量最高的文章张贴如下: 一月 蓝桥杯 基础练习 数的读法 二月 【NCRE四级网络工程师】计算机网络多选题 三月 解决百度网盘限速问题 四月 可能是史上最全的无版权免费图片网站推荐文章 五月 Laravel5.8+LayUI踩坑之路 六月 Laravel5.8学习日常之清除视图缓存 七月 给网站文字添加高逼格"抖音"效果 八月 关于5G的SA与NSA架构 九月 PWA 渐进式Web应用程序 十月 Windows常用软件清单 十一月 MacBook Pro 2019款 入手体验 十二月 PhpStorm Mac / Windows常用快捷键 其中在2019年访客最多的文章是:关于5G的SA与NSA架构 网站访客 这里公布的是从2019年8月20日开始统计,使用Google Analytics统计的数据: 用户访问量:8125,事件数:9.5万,新用户数:2.1万。 Google Analytics 在线报告:点击此处访问(需墙) 关注微信公众号,第一时间获取最新内容,让我们一起变得更强!Debug客栈:订阅本站· 文章归档· 我的项目· 友情链接· 我的使用· 飞湾计划· 摄影展集· 我的主页

© 2026 好站网-HaoZhan.Wang V1.9 版权所有,正在试运行中! 本站由 Zhou's Notes 强力支持!

苏ICP备19065220号-4 公安备案 苏公网安备32100302011680号 萌ICP备20269980号 茶ICP备2026050346号
本站数据 2026年报 版本历史 小黑屋 关于本站 统计代码