Golang Go语言中,刚学,撸了个支付宝发券的程序,为什么性能还比不上 PHP?
Golang Go语言中,刚学,撸了个支付宝发券的程序,为什么性能还比不上 PHP?
下面是主程代码,这是详细代码
func main() {
//解析参数
filePath := flag.String("f", "", "文件路径")
tplId := flag.String("t", "", "模版 ID")
flag.Parse()
//解析密钥
pk, err := ParsePrivateKey()
check(err)
//读取文件
start := time.Now()
csvFile, err := os.Open(*filePath)
check(err)
defer csvFile.Close()
csvReader := csv.NewReader(csvFile)
arr, err := csvReader.ReadAll()
fmt.Println(len(arr))
check(err)
paramsChan := make(chan string, 200)
//统计成功与失败数量
var mutex = &sync.Mutex{}
successNum := 0
failNum := 0
var wg sync.WaitGroup
go func() {
for _, row := range arr {
wg.Add(1)
go func(row []string) { //通过添加显式参数,确保当 go 语句执行时,使用当前 row 值(参考 5.6.1 内部匿名函数中获取循环变量的问题)
defer wg.Done()
params, err := getQuery(row, *tplId, pk)
if err != nil {
fmt.Println(err)
}
paramsChan <- params
}(row)
}
wg.Wait()
close(paramsChan) //安全关闭通道
}()
var wg2 sync.WaitGroup
limit := make(chan bool, 100)
for s := range paramsChan {
wg2.Add(1)
limit <- true
go func(s string) {
defer wg2.Done()
res, err := sendMsg(s)
if err != nil {
fmt.Println(err)
mutex.Lock()
failNum++
mutex.Unlock()
}
if res {
mutex.Lock()
successNum++
mutex.Unlock()
} else {
mutex.Lock()
failNum++
mutex.Unlock()
}
<-limit
}(s)
}
wg2.Wait()
fmt.Printf("发券成功:%d\n", successNum)
fmt.Printf("发券失败:%d\n", failNum)
fmt.Printf("%.2fs elapsed\n", time.Since(start).Seconds())
}
现在如果只整理请求参数,读取 10W 行的 csv 文件,大概耗时 110-120S 左右,耗费内存在 900M 左右。如果加上发送请求的代码,会因为内存消耗太大,直接被操作系统 KILL。
我用 PHP 开 4 个进程+guzzle 异步请求,处理完 10W 数据耗时在 110S 左右。
性能差这么多,这究竟是我代码写的太菜还是因为 PHP 是最好语言?(手动狗头)
更多关于Golang Go语言中,刚学,撸了个支付宝发券的程序,为什么性能还比不上 PHP?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
无脑太菜。等下再看。
更多关于Golang Go语言中,刚学,撸了个支付宝发券的程序,为什么性能还比不上 PHP?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
php 是最好的语言
菜成这样还有救么?
你这前面加个 go 然后后面又 wait,你还不如直接把 go 和 wait 都去了
你一个函数里最后写一个 wait 就行了 一个里面定义两次,太菜了,不多说
老哥,你的性能应该是卡在 ReadAll 处,不要用 ReadAll,改成按行读取试试呢,还有,你这里的等待组,和 goroutine 组合的用法有点够浪啊😈
试下 runtime.GOMAXPROCS(runtime.NumCPU() * 8)
好好想一想哪里该用协程并发,哪里不该用。
我的话会这样写:
定义一个 channel 传消息
定义一个 channel 计数
go func(){ 计数器,不用锁了因为从 chan 读消息 }
go func(){
for line := read_lind(file) {
chan <- line
}
chan <- “end”
}
for msg := <- chan {
go func() { send() } // 这里做并发控制,免得一次全部消息都打出去
}
好像还可以
atomic.AddUint64(failNum);
atomic.AddUint64(successNum);
你这个是串行啊。。。
因缺思厅,像 说的,你有输出的日志吗?是不是时间都耗在 readAll 上了? 有点好奇 php 是怎么读取大文件,这块的性能受限于 IO 吧,和语言没啥关系。除非你 PHP 不是一次 readAll 的
太菜了~
Chan 20 行左右就能实现并发控制,不需要你这些奇怪锁
我写过一 Go 小程序,每天处理 2T 左右的加密后的 SQL 数据,做些统计;性能瓶颈都是 io,跑满网卡,磁盘都是小事。
你这有多少行就启动了多少 goroutine,一个 goroutine 的上下文占用差不多 8K+空间,10W 行大概就 800M 了,实际占用 900M 的话,基本都是创建 goroutine 的操作在消耗资源了。
你发券的话,外部请求明显比不上 range arr,只用一个 goroutine 读,再用一个 chan 发送给几个 goroutine 消费就行了,没必要开海量的 goroutine,开多了反而就出问题了。
哈哈。我用了这么久的 GO,都不敢贴代码。
不想吐槽你的代码逻辑,只想吐槽一下你这代码风格。
因为超过 80 行的函数真心不想看。
佩服楼上几位居然能坚持看完的。
建议看完《代码大全》再来贴代码。
学习了
你要吧 php 的拿出来对比吧
哇塞老哥基础知识好稳,嫉妒一个
多谢指点,昨天晚上太忙了,没来得急回复
多谢指点,待会试试
10W 大概 5M 左右,也不算大文件吧
确实菜,所以需要学习和老哥们指点啊
多谢指点,因为我用 PHP 处理,整理请求在 75S 左右,请求耗时在 40S 左右,所以我一开始就觉得处理数据的需要用并发。
emmm,老哥我刚看了一下,代码在 70 行。不过确实写得菜
时间都花在文件 io 上了吧
我也是这种套路… 我们是在哪里看过一样的东西么…
大佬,这段代码中最后一个 for 循环的作用是什么呢?为了让主进程等待最后几个 goroutine 执行完毕么?
阿西吧。。 这代码怕是骗金币的吧。。😁
go func() {
for _, row := range arr {
wg.Add(1)
go func(row []string) {
defer wg.Done()
params, err := getQuery(row, *tplId, pk)
if err != nil {
fmt.Println(err)
}
paramsChan <- params
}(row)
}
wg.Wait()
close(paramsChan)
}()
这是认真的吗。。。
每个 go 串起来了。。。
and 以后先检查下代码逻辑再提出疑问吧
没有串吧? wait 在 for 循环外部
能够在解决问题后把解法一并贴出的坛友越来越少了,赞楼主👍
贴代码可以用 gist
是
怎么监控内存占用
我是直接 top 看的
在Golang(通常简称为Go)与PHP的性能对比中,遇到Go程序性能不如PHP的情况,可能有几个原因,尽管Go语言本身在并发处理、内存管理和编译速度等方面通常优于PHP。以下是一些可能的原因和建议:
-
代码效率:检查你的Go代码,看是否有不必要的计算、过多的内存分配或低效的算法。优化这些部分可以显著提升性能。
-
并发使用:Go擅长并发编程。如果你的程序没有充分利用Go的goroutines和channels,可能会错过性能提升的机会。确保你的程序在需要时使用了高效的并发模式。
-
外部依赖:如果Go程序依赖于外部服务或数据库,这些服务的性能也会影响整体表现。确保这些依赖项得到优化,并且与Go程序的性能需求相匹配。
-
环境差异:运行环境的差异(如服务器配置、操作系统、网络延迟等)也可能影响性能比较。确保在相似的环境下进行比较。
-
PHP配置:PHP本身也可能经过高度优化,特别是如果它运行在一个高效的Web服务器上,如Nginx与PHP-FPM。确保你的Go程序也运行在最优配置的环境中。
总之,性能问题通常涉及多个因素。建议你使用性能分析工具(如Go的pprof)来识别瓶颈,并针对性地优化代码。同时,确保比较是在公平和可控的条件下进行的。