Go 与 Python 协程(Coroutine)对比演示项目

本项目用于对比和学习 Go 语言(Goroutine) 与 Python(Asyncio) 的协程并发机制。

通过一个模拟执行 3 个不同耗时任务(1秒、2秒、1秒)的经典场景,直观展示两者的编写方式、运行机制与执行效率。


目录结构

text 复制代码
goroutine/
├── main.go      # Go 语言协程实现(含 WaitGroup 与 Channel)
├── main.py      # Python 协程实现(基于 asyncio 与 async/await)
└── README.md    # 项目说明与编译运行指南

一、Go 语言:编译与运行指南

源码:

go 复制代码
package main

import (
	"fmt"
	"sync"
	"time"
)

// worker 模拟耗时任务
// 参数:id 任务编号,seconds 模拟耗时秒数,results 传递结果的 channel,wg 等待计数器
func worker(id int, seconds int, results chan<- string, wg *sync.WaitGroup) {
	defer wg.Done() // 函数退出时通知 WaitGroup 任务已完成

	fmt.Printf("[Go 协程 %d] 开始执行,预计耗时 %d 秒...\n", id, seconds)
	time.Sleep(time.Duration(seconds) * time.Second) // 模拟 I/O 等待

	// 将结果发送到 channel
	results <- fmt.Sprintf("任务 %d 完成,实际耗时 %d 秒", id, seconds)
	fmt.Printf("[Go 协程 %d] 执行完毕!\n", id)
}

func main() {
	startTime := time.Now()

	var wg sync.WaitGroup
	// 缓冲区大小为 3 的 channel,避免发送方阻塞,协程之间用来传递 string 的通信管道
	results := make(chan string, 3)

	// 任务清单:[任务id, 模拟耗时(秒)]
	tasks := [][2]int{
		{1, 1},
		{2, 2},
		{3, 1},
	}

	fmt.Println("=== Go 协程(Goroutine)并发演示 ===")

	// 并发启动任务
	for _, task := range tasks {
		wg.Add(1)
		// 关键字 'go' 启动一个轻量级协程
		go worker(task[0], task[1], results, &wg)
	}

	// 启动一个独立的 goroutine 等待所有任务完成,然后关闭 channel
	go func() {
		wg.Wait()
		close(results)
	}()

	// 从 channel 读取并打印结果
	for res := range results {
		fmt.Printf("--> 收到结果: %s\n", res)
	}

	fmt.Printf("所有任务执行完毕,总耗时: %v\n", time.Since(startTime).Round(time.Millisecond))
}

1. 直接运行源码(开发调试)

在项目根目录下打开终端(PowerShell 或 CMD),直接运行:

bash 复制代码
go run main.go

输出:

复制代码
=== Go 协程(Goroutine)并发演示 ===
[Go 协程 1] 开始执行,预计耗时 1 秒...
[Go 协程 3] 开始执行,预计耗时 1 秒...
[Go 协程 2] 开始执行,预计耗时 2 秒...
[Go 协程 3] 执行完毕!
[Go 协程 1] 执行完毕!
--> 收到结果: 任务 3 完成,实际耗时 1 秒
--> 收到结果: 任务 1 完成,实际耗时 1 秒
[Go 协程 2] 执行完毕!
--> 收到结果: 任务 2 完成,实际耗时 2 秒
所有任务执行完毕,总耗时: 2.002s

2. 编译生成 .exe 可执行文件

方式 A:基础编译(默认命名)

在当前目录下直接执行 go build,会生成与目录同名或默认的 main.exe:

bash 复制代码
go build main.go

执行后会在当前目录生成 main.exe。

方式 B:指定输出文件名(推荐)

使用 -o 参数指定输出的可执行文件名称,例如输出为 goroutine_demo.exe:

bash 复制代码
go build -o goroutine_demo.exe main.go
方式 C:压缩体积编译(生产推荐)

如果希望减小 .exe 文件体积,可以加入 -ldflags="-s -w" 参数:

  • -s:去掉符号表信息。
  • -w:去掉 DWARF 调试信息。
bash 复制代码
go build -ldflags="-s -w" -o goroutine_demo.exe main.go

提示:该参数通常可使编译出的可执行文件体积缩减约 20%~30%,且运行功能完全一致。

方式 D:跨平台交叉编译(在 Linux / macOS 下构建 Windows exe)

Go 支持极其便捷的交叉编译,只需指定环境变量 GOOS 和 GOARCH:

  • Windows PowerShell 环境:

    powershell 复制代码
    $env:GOOS="windows"
    $env:GOARCH="amd64"
    go build -o goroutine_demo.exe main.go
  • Linux / macOS Bash 环境:

    bash 复制代码
    CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o goroutine_demo.exe main.go

3. 运行生成的 .exe 文件

在 Windows 终端中运行:

powershell 复制代码
.\goroutine_demo.exe

二、Python 语言:运行指南

源码:

python 复制代码
import asyncio
import sys
import time

# 兼容 Windows 控制台的中文输出
if sys.platform == "win32":
    sys.stdout.reconfigure(encoding="utf-8")


# worker 异步协程函数
# 在 Python 中,使用 async def 定义协程
async def worker(task_id: int, seconds: int) -> str:
    print(f"[Python 协程 {task_id}] 开始执行,预计耗时 {seconds} 秒...")
    # asyncio.sleep 是非阻塞式的异步等待,不能用 time.sleep(time.sleep 会阻塞事件循环线程)
    await asyncio.sleep(seconds)
    print(f"[Python 协程 {task_id}] 执行完毕!")
    return f"任务 {task_id} 完成,实际耗时 {seconds} 秒"

async def main():
    start_time = time.perf_counter()

    # 任务清单:(任务id, 模拟耗时秒数)
    tasks = [
        (1, 1),
        (2, 2),
        (3, 1),
    ]

    print("=== Python 协程(Asyncio)并发演示 ===")

    # 使用 asyncio.gather 并发调度多个协程,并等待它们全部完成
    # 类似 Go 的 sync.WaitGroup + channel 收集返回结果
    results = await asyncio.gather(
        *(worker(task_id, delay) for task_id, delay in tasks)
    )

    # 打印收集到的结果
    for res in results:
        print(f"--> 收到结果: {res}")

    total_time = time.perf_counter() - start_time
    print(f"所有任务执行完毕,总耗时: {total_time:.3f} 秒")

if __name__ == "__main__":
    # 启动 Python 的异步事件循环
    asyncio.run(main())

确保系统已安装 Python 3.7+(本示例在 Python 3.14 下验证通过),直接在终端执行:

bash 复制代码
python main.py

输出:

复制代码
=== Python 协程(Asyncio)并发演示 ===
[Python 协程 1] 开始执行,预计耗时 1 秒...
[Python 协程 2] 开始执行,预计耗时 2 秒...
[Python 协程 3] 开始执行,预计耗时 1 秒...
[Python 协程 1] 执行完毕!
[Python 协程 3] 执行完毕!
[Python 协程 2] 执行完毕!
--> 收到结果: 任务 1 完成,实际耗时 1 秒
--> 收到结果: 任务 2 完成,实际耗时 2 秒
--> 收到结果: 任务 3 完成,实际耗时 1 秒
所有任务执行完毕,总耗时: 2.015 秒

三、Go vs Python 核心机制对比

对比维度 Go 语言 (Goroutine) Python (Asyncio)
关键字/语法 go func(...) async def / await
底层模型 GMP 调度模型(M:N 线程复用) 单线程事件循环(Event Loop)
多核利用 原生支持多核 CPU 并行调度 单进程单线程循环,受 GIL 限制;多核需结合多进程
调度特点 抢占式 + 协作式调度,普通阻塞自动切出 严格的协作式调度,必须在 await 处主动出让控制权
函数染色 无染色 :普通函数即可用 go 异步运行 有染色 :异步协程必须在 async 上下文中被 await
通信机制 基于 CSP 模型的 Channel(通道)传递消息 函数返回值配合 asyncio.gather 或 asyncio.Queue
分发与部署 静态编译为独立 exe,无依赖即可在目标机器运行 依赖目标机器已安装 Python 解释器及相关依赖环境
相关推荐
ttwuai1 小时前
Go开源后台管理系统推荐:3个官方仓库怎么按技术栈和适用边界比较?
开发语言·golang·开源
codists1 小时前
lexeme和token
python
天赐范式2 小时前
天赐范式第182天:让变异开始存活——主线重启与变异存续条件
python·ar模型·数字生命·天赐范式·动态运行时·稳态方差·变异存续
lusklusklusk2 小时前
Python 四大数据结构详解:元组、列表、集合、字典的特点与增删改查
数据结构·windows·python
打工仔折腾 AI2 小时前
把模型切换交给平台:用蓝耘智能路由搭建商品评论分析工具
java·服务器·前端·后端·python·性能优化·ai agent 实战
个 人 练 习 生2 小时前
C++-----string基本使用详解
开发语言·c++·学习
朝朝辞暮i2 小时前
C++ 第 5 课:else if + 多条件判断 + && / || / !
开发语言·c++
ynchyong2 小时前
python list 地常用操作
开发语言·python
千谦阙听2 小时前
【C++篇】:string类——常用接口、底层原理与深浅拷贝
开发语言·c++·学习·visual studio