V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  lesismal  ›  全部回复第 31 页 / 共 60 页
回复总数  1187
1 ... 27  28  29  30  31  32  33  34  35  36 ... 60  
2023-02-18 17:33:04 +08:00
回复了 Nazz 创建的主题 程序员 go websocket rps, cpu, latency 全面测评
所以,没有必要测试 gobwas/ws ,它还不适合用于商业项目
2023-02-18 17:31:49 +08:00
回复了 Nazz 创建的主题 程序员 go websocket rps, cpu, latency 全面测评
@Trim21 @Nazz
1m-go-websocket 和 gobwas/ws 都是错误的方案,有类似线头阻塞或者 for loop 内阻塞的问题的:io for loop 内单个 conn 阻塞(ws Upgrade 、Read 等调用都有可能当前只收到了 half-packet 而导致阻塞读的等待),这样会导致该 poller 的 for loop 内其他 conn 等待,我有在它的 repo 和 example 的 repo 里聊到相关的,但该作者似乎并不想解决问题、或者他们目前的方案(只是自定制了事件监听、读写并不是非阻塞)无法解决反而是 close issue 假装看不见来解决问题。。。
2023-02-18 12:52:13 +08:00
回复了 machen 创建的主题 程序员 美团:某动态线程池框架是官方开源的么?
@cloudzhou

> 因为这个帖子本身在推广自己 lib (还蹭美团),你又贴了自己链接,导致把你也一顿输出~。

没事的,我以前的一些工作面向的在线连接数比较大,加上有一些旧的技术惯性——服务端方案总是想考虑解决 10k/100k/1000k 的问题,go 这方面不太行所以自己有一些应对方案。看到你们也确实遇到协程爆炸的问题,所以想随便交流下。想推广的时候我就自己也单独发过推广贴了,之前发过,不过感觉 v 站相关的流量不大,所以就不怎么发了,推广随缘,能多多交流就好,哈哈哈


> 回到技术问题:之前没看你这个项目,这次去认真看了~
> 但是,盲猜通过回调实现,比如 Java 里面的 netty ,只有这样才实现少数 io 协程分发
> 结果确实是:
> g.OnData(func(c *nbio.Conn, data []byte) {
> c.Write(append([]byte{}, data...))
> })

其实这里只是 4 层的,要想省协程解决网络相关的协程爆炸的问题,不能主动去阻塞读写,一阻塞就长时间占用协程,所以只能以回调的方式做,其他语言或者 go runtime 也都是这样。

> 刚好我写过 netty 协议的 encoder/decoder ,还写过一些嵌入式类似回调解析协议
> 我的体验就是,回调式符合机器设计,不符合人类思想,维护状态是很累的

因为 4 层 TCP/UDP 只是数据流 /数据报过来,并不能确保每次受到的数据就是 7 层应用协议的一个完整包,加之为了解决协程爆炸问题、用回调的方式收数据、不用阻塞读写,就只能自己维护状态机了。同样的,除了 golang/erlang ,其他语言的高性能异步非阻塞 io 也都是这样做,目前的计算机科学体系里,绕不过这种方案。

> 如果你用两种方式来解析 websocket 协议,就能体现明显差距

其实不是用两种方式来解析 websocket ,而是两种 io 收数据,然后传递给 websocket 解析器。
标准库那种同步解析器阻塞等待读到自己想要的数据量、没办法处理这种非阻塞 io 的 conn 每次不能保证读到它想要的数据就返回 err 的场景。
nbio 的 websocket 解析器只有一解析器,就是你上面说的状态机、异步流解析器。因为这种解析器不关心你单次传递的数据是不是完整包或者多个包,给数据过来就行了,所以它是大于同步解析器的、也能处理同步解析器的场景。
所以就不需要两种解析器,只需要支持多种数据来源就行。
nbio 支持不同的 io 模式是因为,以前的版本只有异步 io 这种,io 协程池读到数据解析出来需要传递给逻辑协程池。如果直接在 io 协程池中处理、当前 conn 处理完当前消息后才能进行其他 conn 的读取、其他 conn 就都慢了。而传递给逻辑协程,这就带来了更多的逃逸、协程切换的成本,buffer 、obj 的生命周期和 pool 优化也都比基于标准库的方案更复杂并且性能差一点。以标准库或者 fasthttp 为例,它们的读 buffer 和各种对象,是同一个协程中 for 循环处理,复用和 pool 优化都很容易,而且如果数据量不是特别大,这些还都是栈上变量,协程亲和性都要好得多。而 nbio 异步 io 这种传递给另外的逻辑协程池,在连接数不是特别大的场景,性能就要差一截了,在连接数阈值达到了的时候才能发挥优势。所以又加上了不同 io 模式的支持,高在线低在线的性能、占用、稳定性更加均衡了。

> 我说的“反感”,就类似,Golang 官方那么努力能你写平铺直叙的同步读写,一把给干回来了

4 层上没办法,原因如前面所述。
但是对于 7 层,其实异步流解析的部分是 nbhttp websocket 框架内做好了的。
你看一下 nbio 的 HTTP 和 Websocket 例子,在你的 HTTP Handler 或者 Websocket 的 OnMessage Handler 里,其实你仍然同平铺直叙的同步逻辑去写业务的。
比如 nbio 对 gin 、echo 的支持,多数业务的 gin 、echo 代码不用变、只要替换 nbio 作为网络层就可以了。
少量的性能场景比如想要 zero copy 的 sendfile 之类的,需要一些业务代码改变,刚好前阵子有人遇到过这问题,更让我没想到的是,gin 、echo 这些自己实现了 Response 竟然还不支持 zero copy ,详情再这里:
https://github.com/lesismal/nbio/issues/263

再以 websocket 为例,比如使用 gorilla/websocket ,是需要自己处理 io 的,比如用一个协程循环读,如果业务涉及广播、还应该用另一个协程+chan 去处理写(否则单个 conn 写阻塞时,广播的 for 循环里其他 conn 就要等待了)。
但是如果用 nbio 的 websocket ,你不需要去自己处理 io 的部分了,只需要写业务逻辑就可以了。

> 我另外一个顾虑是:类似这种依赖某个 x 这么基础组件,有一天 Golang 升级到 xxx 版本了,协程更高效了

未来协程更高效是有可能的,但我估计主要是体现在创建回收复用和调度的效率上,但解决不了根本问题:
1. 因为 go 是有栈协程,所以只要同时存在大量协程,协程的资源占用问题应该是解决不了
2. 大量协程大量上下文变量,GC 的 CPU 消耗也是很难,uber 那些做了很多自己的优化,但仍然压力大

nbio 的方式是相当于把连接数对应的协程数量和上下文省掉了,只是处理当前,而且这个并发度是数量可配置的协程池,超过这个并发度的被协程池内存池资源自然限流等待就相对均衡了。比如协程池数量配置成 5w 这个级别,go runtime 调度和 GC 都不会有压力,业务层即使有阻塞操作,比如每个请求的处理时常 100ms ,1s 能处理 10 轮,5w*10 也能 50w qps/tps ,这数字只是举例子,多数业务比这小得多、应该是足够了。如果不够用,那就还是业务压力大于系统资源能力的问题,怎么都得加机器了。
配置更低的节点想用更少资源,协程池就再配置小点比如 1w 、甚至 1k ,用户自己定制就行

> 然后没有人敢升级,因为这个 x 组件重度依赖,做了好多高科技,没人敢动,这在我们技术上出现过

即使标准库也是有 bug ,所以这个只能是使用者以规范的工程流程做好业务的不同测试,还有就是对于多节点的服务,可以分步、一节点一节点或者一批次一批次地更新技术方案,技术升级把影响范围控制好,稳定的版本不轻易升级。
然后就是社区多互动打磨稳定性了。

> 你这项目我准备 clone 下来看看怎么实现的

欢迎欢迎,多多交流!

> 我刚想说这种回调式写法,协议要使用状态机去实现,就看到你 nbhttp 用状态机解析 http 协议
omg ,这工作量我都不敢想,但是你确定实现了一个完整的 http 协议解析了吗?这工作量可不小

HTTP1.x 这个倒是不难,目前遇到过的最难的部分是 TLS 的异步流解析魔改,因为协议更复杂、版本和代码 if else 分支多、工作量大,所以选择了在标准库 TLS 上直接魔改,爆肝生病了好几次:joy:。
还有更难的一些,目前 nbio 的异步 io 部分只支持了 HTTP1.x ,2.0 、3.0/QUIC 都还没支持,工作量太大,不知道什么时候有档期去搞了。。。
2023-02-17 23:47:08 +08:00
回复了 machen 创建的主题 程序员 美团:某动态线程池框架是官方开源的么?
@cloudzhou
> 说点打击你积极性的话,我非常反感一些很底层操作,使用非官方库的行为,其中包括协程、nio 部分

但凡官方库好用够用消耗少能解决所有痛点,谁闲着蛋疼去重复造轮子啊。如果你是对的,那造轮子的人都是脑子有病似的,字节那帮搞这块地人都该被裁员才对得起资本家了
2023-02-17 23:38:40 +08:00
回复了 machen 创建的主题 程序员 美团:某动态线程池框架是官方开源的么?
@cloudzhou #45

戾气有点重啊,上来就一顿同行相轻,像是吃了火药,没必要。我相信你不是出于恶意,只是对自己技术比较自信,所以觉得别人说的没用。我以前也这样,所以能理解。

> @lesismal 你这逻辑,无非是,net.Conn 都会挂住一个协程,比如 Read 操作,到几百万协程
而你自己写了类似 epoll 监听,只有 readable connection 才会实际占据协程,对不?

差不多是你说的这个意思,传统的其他语言主流高性能的异步 io 部分,也都是如此,非阻塞 io ,可读时占用协程也是短暂占用,所以 io 线程 /协程数量不需要太多。


> 我说的几十万协程,是指实际进行同步 io 的行为,比如消费 kafka 然后 db/redis/rpc 操作等,瞬间击垮对方 /自己系统
对于因为监听 io 阻塞的协程,其实 Go 官方也是足够用的,虽然看起来协程多很多

你前面没有明确说你的几十万协程问题是自家业务这种类似消费 kafka 占用几十万协程,通常遇到的是每个连接一个协程的问题,所以我先入为主了以为是连接数相关的协程爆炸的问题。
但有一个点是相同的,我说的 nbio 之上的逻辑协程池是可控的,配合非阻塞 io ,是可以把这种协程数量爆炸的问题解决的。
比如你们业务阻塞消费 kafka 这种,是因为 topic 太多?是不是可以考虑下改进?比如很多数据 topic 发布到公共的 topic partition ,然后消费者数量就不用那么多,实际的 topic 作为消息的结构体字段,消费者再去自行分流处理。

db/redis/rpc 这些同样的,你们同时几十万个协程去怼下游本身的行为就是不好的呀。要想让自己的服务资源消耗与性能平衡,纵向分层的实现中,每层自己做好限流、连接池协程池这些限制,而不是一股脑都怼下去。

至于标准库一个连接至少一个协程的方案,你这里说够用,但是不代表别人家也够用啊,或者说成本不划算呀。流量大在线高的厂,硬件省 50-70%甚至更高,成本也是不小的。

> 说点打击你积极性的话,我非常反感一些很底层操作,使用非官方库的行为,其中包括协程、nio 部分
真正有你这种需求的,只有有限的 im 、网络转发才需要
the key point: 绝大部分遇到的问题,都是 io 相关,说的天花乱坠,db/redis/log 先要看能不能抗住

放心吧,你不会打击到我的,你自己都列出了几个有我这种需求的场景,而且别人实际业务也有需要的。另外啊,最常见的大厂 http 服务,用我这个替换标准库的话,本身就能省不少硬件、资源占用也可控。

你这些话我觉得有点自相矛盾了。
你前面提出的几十万协程问题,是指实际进行同步 io 的行为,后面楼层又说标准库的同步 io 也足够。足够为啥还造成了几十万协程然后扛不住了呢?那说到底不还是因为标准库同步 io 导致写成数量爆炸的问题吗?那到底标准库是足够不足够呢?


> 很多人做的事情,很像是,把一个长板,构建的更长,然后给大家看,哇,我做了多厉害的工作,然后短板依在。

这是在说我做无用功吗?但是你确定你了解我的库吗?
举个例子,nbio 的 HTTP/Websocket 支持混合 io 模式,混合模式下,支持一定数量内的连接用标准库同步 io ,超过配置阈值的连接由 nbio 的 poller 进行异步 io ,这样的好处是,连接数阈值以内时,性能有保障,我简单压测了下,性能高于标准库、gorilla/websocket 。然后如果海量连接数进来时,照样资源占用可控、服务稳定。
2023-02-17 21:49:17 +08:00
回复了 machen 创建的主题 程序员 美团:某动态线程池框架是官方开源的么?
> @lesismal 我知道,你实现了一个 nio ,替代标准库,不过我的观点不在此,我的意思是,真实的业务,在这个网络层面之前,其他已经挂了,还没到这里,问题终究就是需要对资源进行限制

@cloudzhou 看这个描述,你应该是不知道。。。

nbio 的资源都是可控的,比如协程数量:标准库 net.Conn 方案是每个连接一个协程,所以才会有你前面描述的几十万协程崩了的问题。nbio 里的协程池数量完全是可配置的,比如你百万个连接,不需要每个 Conn 一个协程,少量 io 协程(数量可配置)处理 io ,逻辑协程池(数量可配置、也可以用户定制自己的协程池实现)处理具体的请求。所以比如这百万个连接,并发度只有 1w ,那么同时存在的逻辑协程数量最多也就 1w 。
nbio 的 4 层、HTTP/Websocket 的资源都是可配置的,所以是可控的,只要你不想 OOM ,做合理的配置,就能做到自然均衡限流。
2023-02-17 16:52:21 +08:00
回复了 machen 创建的主题 程序员 美团:某动态线程池框架是官方开源的么?
@cloudzhou
或许我的库能帮助改善 go 的一些状况:github.com/lesismal/nbio
2023-02-15 22:32:56 +08:00
回复了 aapeli 创建的主题 Go 编程语言 有一个 Golang 泛型的问题咨询
@Nazz
v 站回复的 markdown fmt 感人,看这里吧:
https://gist.github.com/lesismal/0cee2bb8d76c7f907a8e2a8401b4fd41
2023-02-15 22:27:44 +08:00
回复了 aapeli 创建的主题 Go 编程语言 有一个 Golang 泛型的问题咨询
@Nazz
看了下简单的基础类型泛型汇编

```golang
// main.go
package main

func SumInt8(a, b int8) int8 {
return a + b
}

func SumInt32(a, b int32) int32 {
return a + b
}

func SumFloat32(a, b float32) float32 {
return a + b
}

func SumFloat64(a, b float64) float64 {
return a + b
}

func SumGenerics[T int8 | int32 | float32 | float64](a, b T) T {
return a + b
}

func main() {
SumInt8(1, 2)
SumInt32(1, 2)
SumFloat32(1.0, 2.0)
SumFloat64(1.0, 2.0)
SumGenerics[int8](1, 2)
SumGenerics[int32](1, 2)
SumGenerics[float32](1.0, 2.0)
SumGenerics(1.0, 2.0)
}
```


```sh
ubuntu@ubuntu:~/generics$ go tool compile -S main.go
ubuntu@ubuntu:~/generics$ go tool objdump main.o
```

```asm
TEXT "".SumInt8(SB) gofile../home/ubuntu/generics/main.go
main.go:4 0x2cb7 01d8 ADDL BX, AX
main.go:4 0x2cb9 c3 RET

TEXT "".SumInt32(SB) gofile../home/ubuntu/generics/main.go
main.go:8 0x2cba 01d8 ADDL BX, AX
main.go:8 0x2cbc c3 RET

TEXT "".SumFloat32(SB) gofile../home/ubuntu/generics/main.go
main.go:12 0x2cbd f30f58c1 ADDSS X1, X0
main.go:12 0x2cc1 c3 RET

TEXT "".SumFloat64(SB) gofile../home/ubuntu/generics/main.go
main.go:16 0x2cc2 f20f58c1 ADDSD X1, X0
main.go:16 0x2cc6 c3 RET

TEXT "".main(SB) gofile../home/ubuntu/generics/main.go
main.go:32 0x2cc7 c3 RET

TEXT "".SumGenerics[go.shape.int8_0](SB) gofile../home/ubuntu/generics/main.go
main.go:20 0x2ed6 8d040b LEAL 0(BX)(CX*1), AX
main.go:20 0x2ed9 c3 RET

TEXT "".SumGenerics[go.shape.int32_0](SB) gofile../home/ubuntu/generics/main.go
main.go:20 0x2eda 8d040b LEAL 0(BX)(CX*1), AX
main.go:20 0x2edd c3 RET

TEXT "".SumGenerics[go.shape.float32_0](SB) gofile../home/ubuntu/generics/main.go
main.go:20 0x2ede f30f58c1 ADDSS X1, X0
main.go:20 0x2ee2 c3 RET

TEXT "".SumGenerics[go.shape.float64_0](SB) gofile../home/ubuntu/generics/main.go
main.go:20 0x2ee3 f20f58c1 ADDSD X1, X0
main.go:20 0x2ee7 c3 RET
```

int8/int32 的泛型生成的汇编是用的 LEAL 指令,非泛型的是 ADDL 指令,虽然都是一条指令但是 LEAL 内存加载应该比 ADDL 慢一点,这应该是你说的换成 int 会快一点的原因吧;
另外,泛型 float32/float64 生成的汇编与非泛型的汇编是一致的,都是 ADDSS/ADDSD 指令,所以性能应该没差别。
2023-02-15 18:59:20 +08:00
回复了 aapeli 创建的主题 Go 编程语言 有一个 Golang 泛型的问题咨询
@Nazz

> 你想表达的应该是 golang 泛型是有开销的, 而不是泛型可以提高性能.

基础类型和非基础类型的性能影响是不一样的

> 同样两份代码, 把参数换成泛型, 不可能会提高性能

你的测试没有提供代码,我没办法做测试结论对应的代码的因果分析


我前面的描述是有说明了场景条件的,但你可能还没仔细看所以没聊到一个点上,大概总结下
1. 主要限定于自定义 struct 类型接口调用,其他语言可能是 class 多态,所以请不要用基础类型来比较性能是否提升
2. 范型本身的实现方案,有办法提高性能的策略,但要看具体语言编译器的实现,go 的目前应该是没有提高,但 c++ rust 那些应该是提高了
3. 编译器优化能够做到范型静多态 /单态化相比于接口或面向对象 class 多态提高性能不是说 go 现在已经提高了,为什么能提高,请看下 #31

如果你熟悉一些 c++,可以简单看下《深度探索 c++对象模型》,对实际业务用处不大,但是对语言这块的理解会有些帮助。编译器理论过于深入我也不懂,其他讲编程语言的书鲜有涉及这块,所以推荐这本书
2023-02-15 16:05:56 +08:00
回复了 aapeli 创建的主题 Go 编程语言 有一个 Golang 泛型的问题咨询
@GeruzoniAnsasu
对,go 是解放了设计阶段的一些束缚,避免了面向对象的鸭嘴兽难题,避免了面对新领域尚无成型的领域设计加之快速迭代需求时顶层设计尾大不掉重构成本过高的问题。
如果项目非常复杂,新人接手之类的,没有自顶向下的类型关系图,这种自下而上地去熟悉代码也是有点心累,要靠个人阅读搜索分析代码和业务理解能力了。但相比于面向对象,这点成本其实要轻松得多。
2023-02-15 15:54:02 +08:00
回复了 aapeli 创建的主题 Go 编程语言 有一个 Golang 泛型的问题咨询
@Nazz #29
> 泛型本来就不能提高性能啊, 只是减少重复工作. 一个 Max 肯定比 MaxInt64, MaxInt32...优雅

你这里所述的是基础类型,我 #17 所说的 "泛型适合运算符重载之类的基础类型场景" 就是支持这样做的,这种场景我对使用泛型没有异议。

"泛型本来就不能提高性能啊" 是不正确的,只是 go 目前的泛型实现方案对自定义结构体类型没带来性能提升,但是其他一些语言是做到了的。我觉得可能是由于 go 自带 runtime 面临着更多复杂性,所以目前阶段没有支持这种优化,或许随着 go 未来版本编译器的优化也能带来这些提升。

泛型"能够"性能提升的场景主要是自定义的结构体类型相关的。
你可以先找些资料来研究下,比如面向对象多态的函数表,比如 c++模板静多态,我前面提到的 "泛型会让你的 Go 代码运行变慢",帖子里有讲比我更专业更深入的,引用一段落:
"从历史上看,C++、D 乃至 Rust 等系统语言一直采用单态化方法实现泛型。造成这一现实的原因很多,但总体来说就是想用更长的编译时间来换取结果代码的性能提升,并且只要我们能提前把泛型代码中的类型占位符替换成最终类型、再进行编译,就可以极大优化编译流程的性能表现。装箱方法就做不到这一点。另外,我们还可以对函数调用进行去虚拟化以回避 vtable ,甚至使用内联代码实现进一步优化。"

甚至不需要去研究这些,你可以站在编译器和运行时的角度自行想象一下比如:interfaceA 的一个实例在进行方法调用时,如何通过这个实例的指针实现方法调用?
首先你得知道这个实例的类型,否则A类型调用到B类型的方法上去就乱套了,go 的指针是胖指针,指向的内容一部分是类型元信息,一部分是指向值本身。要实现实例化调用,首先要通过这个 interfaceA 实例的指针去解引用取得类型信息、找到函数表,然后再把值和函数结合起来使用。这是由 runtime 来处理的,运行时才能搞定。
而静多态 /单态化,比如 c++模板,是编译期就生成了对应类型的代码,与上面说的 interfaceA 由运行时处理对比一下,静多态 /单态化可以把 runtime 先确定类型信息这一步省掉,虽然只是一些简单的指针操作,但量大积累起来,性能差距就拉开了。
2023-02-15 13:28:02 +08:00
回复了 aapeli 创建的主题 Go 编程语言 有一个 Golang 泛型的问题咨询
@lesismal #27 更正
我觉得这样说不太正确。接口与面向对象是不同的:
1. 面向对象是自顶向下的约束,非父类本身或者子孙类无法作为祖辈参数的实例入参传入;
2. 接口没有强制的向下约束,而是以更自由松散的方式、按需定以按劳分配,完全可以根据需求、抽取需要实现的方法集合作为一个单独的接口定以去作为其他公共形式的使用。可能是由于大家平时一些自定义类型需要去实现标准库已经定义了的接口,才会有这种被约束的错觉。
2023-02-15 13:26:10 +08:00
回复了 aapeli 创建的主题 Go 编程语言 有一个 Golang 泛型的问题咨询
@GeruzoniAnsasu #25
> 接口有个很大的问题是不能只实现部分

我觉得这样说不太正确。接口与面向对象是不同的:
1. 面向对象是自顶向下的约束,非父类本身或者子孙类无法作为祖辈参数的实力传入;
2. 接口没有向下约束,而是以更自由松散的方式、按需定以按劳分配,完全可以根据需求、抽取需要实现的方法集合作为一个单独的接口定以去作为其他公共形式的使用。可能是由于大家平时一些自定义类型需要去实现标准库已经定义了的接口,才会有这种被约束的错觉。

比如 struct A 实现了 M() X() Y(), struct B 实现了 N() X() Y(),泛型需求是需要在泛型方法里调用 X() Y()。可以定义一个 interface XY{ X() Y() } 抽取他们公共的部分,以接口的方式替代泛型,当然,这个单独的定以是一点额外的成本,但并不算复杂。

标准库的很多接口定义,是根据多年的工程实践总结出来的一些通用抽象,这些是属于基础设施、系统编程范畴的。
而相比于标准库、我们基于其上构建的,基础库也好、业务需求也好,更多的是基于自己需要来进行定义,这些自定义的约束来自自己的设计、可以灵活处理,并不需要太被标准库约束。
2023-02-15 13:10:15 +08:00
回复了 aapeli 创建的主题 Go 编程语言 有一个 Golang 泛型的问题咨询
@Nazz

> 泛型声明里面限定了 int, float 之后自然可以做加减乘除, 更复杂的操作即使有重载操作符也不够用, 我认为泛型主要是给写库的人使用的

泛型也好,接口也好,或者其他语言的面向对象多态,以及 c++的模板静多态(编译期为每种实际类型生成代码性能更好),所有这些都是为了系统设计时的公共操作抽象做语法基础。
所以不管是泛型还是接口,都是需要这些“同类”obj 具有一组相同的操作(运算符或者方法)。

就 go 而言,除去基础类型能支持运算符,对于自定义类型的 struct ,只能通过方法来实现相同操作,而对于多个类型的同名同形式方法,以接口的方式作为其他方法的参数要比以泛型的方式来定义其他方法更简洁明了,而且版本兼容性也更好。

另外就是性能,截至目前,自定义类型的泛型性能应该是不够好的,可以搜一下 “泛型会让你的 Go 代码运行变慢” 这个帖子看看,或者其他关于范型性能的帖子。
所以对于写库的人来说,如果出于性能考虑,目前的泛型也是应该放弃,连接口都不要用而是把接口访问自己元类型这层中转的指针操作也省去、自己手撸不同类型的实现才是最好的选择,而对于写库的作者,其实用不用范型节省不了太多工作量,毕竟基础设施的领域不像 CURD 那样经常搞很多需求。
当然,如果后续版本的编译器能像 c++模板那样以静多态的方式来提高性能是最好了,然后如果性能敏感的场景来替代接口的方式,也可以不用手撸多种类型的实现替代泛型了

> 不熟悉模板元编程,但模仿 cpp 的话无疑会让 go 变复杂许多

并不是模仿 c++,而是目前 go 的泛型除去基础类型范畴,既没有性能提升也没有使代码更加优雅简洁。反倒是很多人为了泛型而泛型、本来不需要泛型的地方都想用泛型,反倒把 go 搞复杂了。
2023-02-15 11:26:54 +08:00
回复了 aapeli 创建的主题 Go 编程语言 有一个 Golang 泛型的问题咨询
@Nazz #18
对比下 c++,因为 c++有运算符重载,所以模板这种泛型里类也可以直接加减乘除这些运算符、因此不需要使用方法如 a.Sum(b)。而 go 里没有运算符重载,很多算法数据结构里即使使用泛型,仍然需要以接口的形式由 struct 实现接口,然后用 a.Sum(b)之类的函数调用方式来处理。显而易见,既然这种地方已经使用接口方法了,这里的泛型就是多余的了。
多数时候是在使用基础类型为主的地方,使用泛型可以节约代码、不用为每种类型都去实现一个 /一组方法或者单个方法内再做类型转换。而本来接口、切面就能做的地方,泛型是画蛇添足。

所以有了我在#17 的观点。

自从支持了泛型以后,不少人为了用泛型而用泛型,让 go 代码变得更丑陋了,很不希望看到一些大厂“架构师”又来污染放毒,因为太多小白会跟风,最终劣币驱逐良币。
2023-02-14 22:57:00 +08:00
回复了 aapeli 创建的主题 Go 编程语言 有一个 Golang 泛型的问题咨询
@Nazz
如果入参不是对应具体 interface{...}类型也是编译期就失败的。

@aapeli
个人感受是:go 的泛型适合运算符重载之类的基础类型场景,自定义类型通常用 interface{...}或者切面更加简洁清晰、硬要为了用泛型而去用泛型,可能会让代码更难看。

再根据我浅薄的 go 泛型使用经验(不超过 10 分钟),能用接口、切面解决的问题不要用泛型就是最优解。
——不一定对,仅供各位参考
怀念那些用牛皮纸包书皮的青春岁月
2023-02-07 15:53:14 +08:00
回复了 Nazz 创建的主题 程序员 求教,个人开源项目如何才能快速积累 star
@Nazz 来试试我这个,也支持 http ,github.com/lesismal/arpc
2023-02-07 14:52:42 +08:00
回复了 Nazz 创建的主题 程序员 求教,个人开源项目如何才能快速积累 star
@bitkuang8 一看当前 599 ,连项目是做啥都没看我就点了,图个 600 的喜庆
1 ... 27  28  29  30  31  32  33  34  35  36 ... 60  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5591 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 26ms · UTC 03:38 · PVG 11:38 · LAX 19:38 · JFK 22:38
Developed with CodeLauncher
♥ Do have faith in what you're doing.