之前我用Python写了一个爬虫项目,主要是抓电商价格。 一开始数据量不大,跑得挺欢。 直到有一天,数据量突然涨到每天300万条,我同时开了2000个爬虫任务,结果内存直接飙到2.3GB,然后卡死,还得手动kill。 后来同事用Go写了一个同样的抓取器,他说他用了goroutine池,跑起来内存才480MB,而且从来没有卡死过。 我靠,这个数字对比让我当场破防。 于是我决定花两周时间学Go,然后把自己的项目重写一遍。
学习Go的过程并没有我想象中那么难,但有几个地方真的反人类。 比如切片和数组的区别,我写了三年Python从没关心过这个,Go里如果搞混,编译倒是能过,但运行时会panic。 最让我纠结的是并发模型,Python的asyncio你需要把函数定义成async,然后await调用;Go呢,直接go func()然后扔到channel里,一切看起来简单,但一旦你想控制并发上限,就得自己搞WaitGroup或者Semaphore。 我第一次写的时候,为了省事,用了十几个全局变量去记录状态,结果跑起来数据时对时错,后来用go vet和race detector一查,才发现有数据竞争。 说实话,这个调试过程比写代码还费时间。
为了让自己死心,我做了个很简单的对比实验:一个JSON解析接口,从Redis里读数据然后返回。 Python用FastAPI,Go用Gin,同样跑在一台4核8G的云服务器上。 先用压测工具打500并发,持续三分钟。 Python平均延迟450ms,P99直接飙到1.2秒,内存占用一度到7.8GB,服务器差点被拉黑。 Go呢,平均延迟38ms,P99是96ms,内存稳定在1.1GB,CPU占用还不到40%。 这个结果确实震撼,但我也清楚,Python的启动时间和解释器开销摆在那里,拿它跟编译语言比性能本来就是欺负人。
现在说说我自己的结论。 网上一堆人说“没有最好的语言,只有最适合的”,这种话跟没说一样。 我的个人经验是:如果你的项目要活过一年,而且不只是脚本,比如是Web服务、工具链、或者需要高并发的系统,那就直接上Go,别犹豫。 但如果你就是拿来做数据分析、调个API、写点自动化脚本,或者做机器学习原型,Python依然无敌。 另外,Go的生态其实没有吹的那么好,很多库都缺人手维护,比如我找了一圈密码哈希的库,官方推荐的golang.org/x/crypto/bcrypt还行,但另一个库的API跟文档对不上,害我调了半天。 反正我现在主力是Go,但也会用Python写一些快速验证的东西,就像用菜刀砍树,你非说菜刀不好,那也不对,只是工具不趁手。