使用 Go 语言每秒百万量级的模拟数据生成优化总结

本文旨在深入研究如何使用Go语言优化模拟数据生成性能。我们将介绍三个不同版本的代码实现,并详细分析它们的性能和优点。 版本一:基础实现 首先,让我们来看看第一个版本的代码,这是一个基础实现,没有引入并发。以下是版本一的核心代码: func randomVersion1(labels []int) *strings.Builder { str := &strings.Builder{} for i := 0; i < len(labels); i++ { switch labels[i] { case 0: str.WriteString(strconv.Itoa(rand.Intn(2) - 1)) case 1: str.WriteString(fmt.Sprintf("%.8f", 0.1+rand.Float64()*(1-0.1))) } if i < len(labels)-1 { str.WriteString(",") } } return str } func TestVersion1(t *testing.T) { f, _ := os.OpenFile(filename, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644) buf := bufio.NewWriter(f) s := time.Now() buf.WriteString(fmt.Sprintf("%s\n", header)) for i := 0; i < 1000000; i++ { buf....

九月 25, 2021 · 3 分钟 · Mioto Yaku

Bitwarden 白皮书简析

1Password 太贵了,$2.99 和 $4.99 分别对应单人和家庭套餐!!!现在的 1password 收费模式也转向了订阅付费,同时架构也转向了 CS 架构,所以本质上和 Bitwarden 也差不多了。 Bitwarden 是一款自由且开源的密码管理服务,用户可在加密的保管库中存储敏感信息(例如网站登录凭据)。Bitwarden 平台提供有多种客户端应用程序,包括网页用户界面、桌面应用,浏览器扩展、移动应用以及命令行界面。Bitwarden 提供云端托管服务,并支持自行部署解决方案。 – 维基百科 Bitwarden 安全原则 端到端加密:所有的密码和私人数据都通过 AES-256 进行加密。所有的加密密钥均在客户端生成和管理,加密过程均在客户端完成。 零知识加密:Bitwarden 服务端不存储你的主密钥以及加密密钥,你的数据使用你的个人邮箱以及主密钥进行加密。 源代码可用:代码完全开源,并可自行编译使用。 隐私设计:所有登录信息在你的设备中进行加密后在存储到 Bitwarden服务器的保管库中,并将保管库同步到所用你的设备,你的数据采用 AES-CBC 256 位加密、加盐散列和 PBKDF2 SHA-256 进行密封。 安全审计与合规:Open source and third-party audited, Bitwarden complies with AICPA SOC2 Type 2 / Privacy Shield, GDPR, and CCPA regulations. Bitwarden 核心概念 主密钥(Master Key) 最核心的密钥,所有后续的密钥和加密密钥均通过主密钥派生,主密钥也是解密所有登录信息以及私人数据的唯一密钥,丢失会导致无法获取已经保存的数据,泄漏将导致所有的数据公之于众。所以主密钥复杂点毕竟你所有的密钥都不需要记了,主密钥在特别简单岂不是很危险? 伪代码: masterKeyHash = pbkdf2(masterKey, email) 主密钥哈希 用来鉴权登录,身份认证,从 Bitwarden 服务端获取密码保管库。 伪代码: masterKeyHashHash = pbkdf2(masterKeyHash, masterKey) 扩展主密钥(Stretched Master Key) 通过主密钥派生出加密密钥和签名密钥,并将两个密钥拼接成扩展主密钥。...

九月 24, 2021 · 1 分钟 · Mioto Yaku

Plan9 汇编入门讲解

为什么要看 Plan9 汇编?如果你是 Go 开发者,去学习和理解一下 Plan9 是很有必要的,因为它可以解决你对一段代码的理解(为什么这样不行?那样却可以?)。 Plan9 不同于 AT&T 和 Intel 汇编器,但是懂这两个汇编语法的话对理解 Plan9 还是有很大帮助的。 疑惑 // 为什么这个函数的返回值会是 -1 func demo1() int { ret := -1 defer func() { ret = 1 }() return ret } // output: -1 // 为什么这个函数的返回值会是 1 func demo2() (ret int) { defer func() { ret = 1 }() return ret } // output: 1 相信大部分人都看过类似的解答,demo1 中是临时变量导致的,而 demo2 中没有临时变量,这是最终结果。 在汇编层面到底做了什么?本文将会探讨这个问题。(本文所使用的平台是 MacOS AMD64)不同的平台指令集和寄存器都不一样。 基础 通用寄存器 下面是通用通用寄存器的名字在 IA64 和 plan9 中的对应关系:...

一月 19, 2021 · 5 分钟 · Mioto Yaku

Go HTTP Response 写超时导致的 EOF 错误

前天在联调过程中出现了一个神奇的错误, 错误在 client 端的表现为 http 请求错误 Get "http://127.0.0.1:8800": EOF, 但是服务端却没有任何 异常 所有的日志都是正常执行 由于只有 client 端的错误, 所以 Google 搜索的处理结果全都不是实际场景导致的(并没有怀疑到服务端出了问题), 无奈只能抓包, 最终问题得以解决 原因 server 端处理请求耗时 30s, 但是 http.Server 的 write timeout 设置的时间是 10s, 所以在 handler 处理请求完毕的时候, server 端和 client 端的连接已经被关闭了 但是由于 server 端写入的 data 远远小于 http/net 包中设定的 write buffer 缓冲大小(4096 byte), 所以 bufio 的 Write 方法并没有返回 error 抓包 源码: https://github.com/yakumioto/demo-response-write-timeout 由于测试环境太过复杂, 所以写了个 demo 复现了整个流程, 以下是 wireshark 导出的 svc 由此可以看出: 客户端通过三次握手和服务端建立了 TCP 连接 客户端正常的发送了 HTTP Request 请求 正常的保持了一段时间的 Keep-Alive 服务端通过四次挥手和客户端断开了连接 "No....

十月 1, 2020 · 4 分钟 · Mioto Yaku

神经网络的数据基础

神经网络的数据表示 张量(tensor) 是一个数据容器, 它包含的数据几乎总是数值数据, 因此它的数字容器, 张量是矩阵向任意维度的推广, 维度(dimension) 通常也叫作 轴(axis). 标量(scalar): 仅包含一个数字的张量叫作 标量(标量张量, 零维张量, 0D 张量), 一个 float32 或 float64 的数字就是一个标量张量. x = numpy.array(12) 向量(vector): 数字组成的数组叫作 向量(一维张量, 1D 张量), 张量有一个轴. x = numpy.array([12, 3, 6, 14, 7]) 矩阵(matrix): 向量组成的数组叫作 矩阵(二维张量, 2D 张量), 矩阵有两个轴(行, 列). x = numpy.array([ [5, 78, 2, 34, 0], [6, 79, 3, 35, 1], [7, 80, 4, 36, 2]]) 3D张量与更高维的张量: 矩阵组成的数据叫作 3D 张量, 3D 张量组成的数组叫作 4D 张量, 以此类推....

九月 6, 2020 · 3 分钟 · Mioto Yaku

Hyperledger Fabric 加入通道时遇到 channel doesn't exist 问题

据同事说 node sdk@v2.x.x 版本中没有对网络操作相关的 API 实现, 所以只能自己照着 v1.4.x 版本的 手撸底层代码, 但是在实现 JoinChain 这个功能时出现了 channel doesn't exist 错误 原因 // SignedProposal 部分结构 { "proposal_bytes": { "header": { "channel_header": { "channel_id": "" }, "signature_header": { "creator": { "mspid": "", "id_bytes": "" } } }, "payload": "" }, "signature": "" } 当 peer 收到 client 发来的 SignedProposal 时, 会进行签名校验 根据 proposal_bytes.header.channel_header.channel_id 获取对应的 mspMgmtMgr, 如果此时通道不存在, 则会创建一个未经初始化的 mspMgmtMgr 根据 proposal_bytes.header.signature_header.creator.mspid 获取对应的 mspManagerImpl, 但是由于 mspMgmtMgr 未初始化, 所以直接返回了 channel doesn't exist 源码追踪 重要的事情说三遍...

六月 27, 2020 · 3 分钟 · Mioto Yaku

Hyperledger Fabric peer block 的交付流程详解

本文基于 hyperldeger fabric 1.4.7 进行代码追踪讲解 假设场景描述: peer 重启场景 peer 有 user channel peer 使用的是 goleveldb peer 的 core.peer.gossip.orgLeader 为 true 流程简介 初始化账本根据账本中保存的 channel id 创建通道实例, 并初始化与之对等的 gossip 服务, 用 来接收对应通道的最新的 配置或交易 block, 接收到 block 后, 经过 Verify, Validate, Validate RW sets 三个验证步骤, 提交给 Ledger Commiter 进行写入文件, 并将当前通道的 blkMgrInfo 更新到最新状态 源码追踪 伊始: main -> node.Cmd -> startCmd -> nodeStartCmd -> serve peer.Initialize 文件: core/peer/peer.go:241 初始化 ledgermgmt, 里面做的事情太多了, 要讲清楚有点困难建议大家自己去看看, 里面主要做的就是 各种初始化工作 // /var/hyperledger/production/ledgersData 下有这些东西, 这里面的工作跟此目录有关 // chains/index goleveldb: 保存了所有通道的最新状态信息 // fileLock goleveldb: 用于锁程序的,文章最末尾有介绍 // historyLeveldb goleveldb: 保存历史交易的 // ledgerProvider goleveldb: 保存的是 chain ids, 也就是通道id // pvtdataStore goleveldb: 存储私有数据库 // stateLeveldb goleveldb: 世界状态数据库, 可以替换为 couchdb // 这两个我不确定没有细追 // configHistory 看名字应该是保存了 config block 相关的东西....

六月 15, 2020 · 4 分钟 · Mioto Yaku

Go 删除 Slice 中的某一个值

方法一 优点: 速度最快 缺点: 会导致切片数据顺序改变 a := []string{"A", "B", "C", "D", "E"} i := 2 a[i] = a[len(a)-1] // 将数组的最后一位赋值给需要删除的 index 上 a = a[:len(a)-1] // 移除掉最后一个没用的数据 // Output: // [A B E D] 方法二 优点: 速度会随着切片长度改变 缺点: 保持原有切片顺序 a := []string{"A", "B", "C", "D", "E"} i := 2 a = append(a[:i], a[i+1:]...) // Output: // [A B D E] Benchmark goos: linux goarch: amd64 pkg: github.com/yakumioto/go-example/benchmark/delete-element-slice Benchmark1 Benchmark1-4 1000000000 0....

六月 3, 2020 · 1 分钟 · Mioto Yaku

Fabric 中 etcdraft 共识讲解

为什么要通过 etcdraft 来进行共识? 我觉得有以下原因 solo 并不适合大多数场景, 例如: 组织A, 组织B, 都想在自己放置共识节点 kafka 虽然能满足以上需求, 但是 kafka 加上 zookeeper 需要额外部署并且实在是太重了, 不方便部署 所以基于 etcdraft 的共识来了, 解决了以上的痛点 重要的话说三遍! 千万不要错过文章中的源码部分, 里面有很多很多的注释!!! 千万不要错过文章中的源码部分, 里面有很多很多的注释!!! 千万不要错过文章中的源码部分, 里面有很多很多的注释!!! 核心接口 以下是我认为实现 etcdraft 共识核心的接口 // ClusterServer 集群Server接口 type ClusterServer interface { Step(Cluster_StepServer) error } // ClusterClient 集群Client接口 type ClusterClient interface { Step(ctx context.Context, opts ...grpc.CallOption) (orderer.Cluster_StepClient, error) } // Handler 用于共识的两个接口 type Handler interface { OnConsensus(channel string, sender uint64, req *orderer.ConsensusRequest) error OnSubmit(channel string, sender uint64, req *orderer....

一月 15, 2020 · 8 分钟 · Mioto Yaku

Go 100 行实现 HTTP(S) 正向代理

目标是现实一个 HTTP HTTPS 的代理服务器, 目前代理的实现方法有两种 普通代理: 这种代理扮演的是中间人角色, 对于客户端来说, 它就服务器, 对于服务端来说, 它是客户端, 它负责在中间来回传递 HTTP 报文 隧道代理: 它是通过 HTTP 正文部分(body) 完成代理, 以 HTTP 的方式实现基于 TCP 的应用层协议代理, 这种代理使用 HTTP 的 CONNECT 方法建立连接 这是一次 HTTP 的请求, 用 \r\n 进行换行, 碰到连续两个 \r\n 后内容为请求数据, 分为以下几个部分 请求行 (request line) 请求头 (header) 空行 请求数据 (body) curl -Lv http://baidu.com > GET / HTTP/1.1 > Host: baidu.com > User-Agent: curl/7.68.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1....

八月 21, 2019 · 2 分钟 · Mioto Yaku