Python中Golang Goroutine与Python Asyncio性能对比,谁更快?
有人说 如果说 Golang 的 Goroutine 比 Python 的 Asyncio 快,就是在黑 Go,这是真的吗? Golang Goroutine 与 Python Asyncio 的性能对比,谁快??
Python中Golang Goroutine与Python Asyncio性能对比,谁更快?
这个问题其实有点“关公战秦琼”的味道,因为它们的设计目标和应用场景有本质区别。简单说,在纯I/O密集型、高并发、单进程的场景下,asyncio可以非常快,甚至在某些基准测试中接近Go。但在需要利用多核CPU进行并行计算,或者涉及大量阻塞型I/O(比如文件操作、某些数据库驱动)的场景下,Go的Goroutine凭借其真正的多线程和更底层的调度器,通常有碾压性优势。
核心差异在于:
- 并发模型:Goroutine是多线程的,由Go运行时调度到多个OS线程上,能真正利用多核CPU。Asyncio是单线程的协作式多任务,所有任务在一个线程里切换,遇到CPU计算就卡住。
- 阻塞代价:在Goroutine里进行阻塞操作(如网络请求、sleep),只会阻塞当前Goroutine,其他Goroutine照常运行。在Asyncio里,如果你在一个协程里用了阻塞的代码(没用
await),整个事件循环都会被卡住。 - 内存开销:启动一个Goroutine的栈初始只有几KB,可以轻松创建成千上万个。Asyncio的Task对象开销也很小,但Python解释器本身和GIL是更大的瓶颈。
给你看个直观的例子,模拟高并发HTTP请求:
Python Asyncio版本 (用aiohttp)
import asyncio
import aiohttp
import time
async def fetch(session, url):
async with session.get(url) as response:
await response.text()
return response.status
async def main():
url = "http://httpbin.org/delay/1" # 模拟一个延迟1秒的服务器
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, url) for _ in range(1000)]
start = time.time()
await asyncio.gather(*tasks)
end = time.time()
print(f"Asyncio 完成1000个请求耗时: {end - start:.2f}秒")
asyncio.run(main())
Go Goroutine版本
package main
import (
"fmt"
"io/ioutil"
"net/http"
"sync"
"time"
)
func fetch(url string, wg *sync.WaitGroup) {
defer wg.Done()
resp, _ := http.Get(url)
defer resp.Body.Close()
ioutil.ReadAll(resp.Body)
}
func main() {
url := "http://httpbin.org/delay/1"
var wg sync.WaitGroup
start := time.Now()
for i := 0; i < 1000; i++ {
wg.Add(1)
go fetch(url, &wg)
}
wg.Wait()
elapsed := time.Since(start)
fmt.Printf("Go 完成1000个请求耗时: %.2f秒\n", elapsed.Seconds())
}
跑一下你会发现:在这个纯网络I/O的场景下,两者性能会非常接近(可能都在2-3秒左右完成),因为时间主要花在等待远程服务器响应上。Asyncio的单线程事件循环处理这种“等待”效率很高。
但是,如果我们把任务改成CPU密集型的,比如计算斐波那契数列:
# Asyncio - CPU密集型是灾难
async def cpu_bound_task(n):
# 模拟CPU计算
def fib(n):
if n <= 1:
return n
return fib(n-1) + fib(n-2)
return fib(n) # 注意:这里没有await,是阻塞调用!
async def main():
tasks = [cpu_bound_task(35) for _ in range(10)] # 计算10次fib(35)
start = time.time()
await asyncio.gather(*tasks) # 这会顺序执行,因为GIL和CPU计算阻塞事件循环
end = time.time()
print(f"Asyncio CPU任务耗时: {end - start:.2f}秒")
// Go - 轻松利用多核
func cpuBoundTask(n int, wg *sync.WaitGroup) {
defer wg.Done()
fib(n)
}
func fib(n int) int {
if n <= 1 {
return n
}
return fib(n-1) + fib(n-2)
}
func main() {
var wg sync.WaitGroup
start := time.Now()
for i := 0; i < 10; i++ {
wg.Add(1)
go cpuBoundTask(35, &wg) // 10个goroutine并行计算
}
wg.Wait()
elapsed := time.Since(start)
fmt.Printf("Go CPU任务耗时: %.2f秒\n", elapsed.Seconds())
}
这时候Go会比Python快N倍(N≈你的CPU核心数),因为Go的Goroutine能真正并行跑在多个核上,而Python的asyncio会被GIL锁住,只能在一个核上顺序执行。
所以结论是:
- 选Asyncio:如果你的应用是典型的Web后端、爬虫、微服务网关,主要在做网络I/O,并且你熟悉Python生态。它的性能对于很多场景已经足够好,开发效率高。
- 选Go:如果你需要处理大量CPU密集型任务、需要真正的并行计算、或者就是想要更高的并发性能和更低的内存开销,不想操心GIL问题。
一句话建议:I/O密集型且代码风格合适就用asyncio,追求极致并发和CPU并行或厌烦GIL就选Go。
没必要去比,不是一个量级的东西,一个编译行语言,一个解释型语言
python 的 asyncio…大坑
什么坑?
本质上都是 producer-consumer,但是 python 因为多个原因性能比较受限。
async io 性能好一些的可以参考 .NET 的 Task-based async API。
掘金的那一篇文章??
确实是在黑 go, go 的效率和 java 相当, goroutine 强在跨线程的调度器, Asyncio 有啥? 为了支持 Asyncio, 每一个涉及到 io 的应用都得改造过. 不懂为啥 2 个要放在一起比.
感觉这是在比火箭和导弹哪个更快
一黑黑两个,不是做同样事情的。
抛开快不快,还有写的舒不舒服…
没有任何可比性 后者慢一个量级


