导读:本期聚焦于小伙伴创作的《如何利用Go或Rust调用Python脚本实现真正的并行执行?》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何利用Go或Rust调用Python脚本实现真正的并行执行?》有用,将其分享出去将是对创作者最好的鼓励。

在很多混合技术栈的项目中,我们可能会需要用Go或Rust作为主程序,调用Python脚本完成机器学习推理、数据清洗等特定任务。但不少人会发现,即使开启了多个协程或线程,Python脚本的执行还是串行化的,没法实现真正的并行。这背后主要是Python全局解释器锁的限制,以及Go和Rust常规调用Python的方式没有正确隔离运行环境导致的。

如何利用Go或Rust调用Python脚本实现真正的并行执行?

为什么常规调用无法实现真正并行

Python的全局解释器锁(GIL)会保证同一时刻只有一个线程执行Python字节码,即使在多核CPU上,多线程的Python程序也无法利用多核实现并行。如果我们在Go中用协程直接调用Python,或者在Rust中用线程直接拉起Python解释器,所有的Python脚本实例都会共享同一个GIL,最终结果就是串行执行。

要实现真正的并行,核心思路是让每个Python脚本实例运行在独立的进程中,这样每个进程都有自己独立的GIL,互相之间不会阻塞,就可以利用多核CPU实现并行执行。

Go调用Python脚本实现并行

Go本身支持多协程,但调用外部命令是操作系统级别的进程创建,我们可以利用Go的协程同时拉起多个Python进程,实现并行执行。下面的示例会同时启动3个Python脚本实例,每个实例执行不同的任务。

Go调用代码示例

package main

import (
    "fmt"
    "os/exec"
    "sync"
    "time"
)

func main() {
    // 要执行的Python脚本路径,这里假设你有三个不同的脚本,或者同一个脚本传不同参数
    scripts := []string{"./task1.py", "./task2.py", "./task3.py"}
    var wg sync.WaitGroup

    startTime := time.Now()
    // 遍历脚本列表,为每个脚本启动一个Go协程,在协程中创建独立的Python进程
    for _, script := range scripts {
        wg.Add(1)
        go func(s string) {
            defer wg.Done()
            // 执行Python脚本,这里的python命令需要确保环境中有对应解释器
            cmd := exec.Command("python3", s)
            // 获取执行输出
            output, err := cmd.CombinedOutput()
            if err != nil {
                fmt.Printf("执行脚本%s出错:%v\n", s, err)
                return
            }
            fmt.Printf("脚本%s执行完成,输出:%s\n", s, output)
        }(script)
    }

    // 等待所有协程执行完成
    wg.Wait()
    fmt.Printf("所有任务执行完成,总耗时:%v\n", time.Since(startTime))
}

对应的Python测试脚本示例

这里给出其中一个Python脚本的示例,其他两个可以类似编写,只是执行的任务不同:

import time
import sys

def task():
    # 模拟耗时任务,比如数据处理或者模型推理
    print(f"任务开始执行,进程ID:{sys.argv[0]}")
    time.sleep(2)
    print("任务执行完成")

if __name__ == "__main__":
    task()

这种方式下,每个exec.Command都会创建一个独立的Python进程,这些进程之间互不影响,GIL也不会互相阻塞,所以三个脚本会同时执行,总耗时大概是2秒左右,而不是串行的6秒。

Rust调用Python脚本实现并行

Rust的标准库也支持创建子进程,同时可以结合Rust的线程或者async运行时实现并行拉起多个Python进程。下面的示例用Rust的标准库线程来并行执行多个Python脚本。

Rust调用代码示例

use std::process::Command;
use std::thread;
use std::time::Instant;

fn main() {
    let scripts = vec!["./task1.py", "./task2.py", "./task3.py"];
    let mut handles = Vec::new();
    let start_time = Instant::now();

    // 遍历脚本列表,为每个脚本启动一个线程,在线程中创建Python子进程
    for script in scripts {
        let handle = thread::spawn(move || {
            // 执行Python脚本
            let output = Command::new("python3")
                .arg(script)
                .output()
                .expect("执行Python脚本失败");
            if output.status.success() {
                println!("脚本{}执行完成,输出:{}", script, String::from_utf8_lossy(&output.stdout));
            } else {
                println!("脚本{}执行出错:{}", script, String::from_utf8_lossy(&output.stderr));
            }
        });
        handles.push(handle);
    }

    // 等待所有线程执行完成
    for handle in handles {
        handle.join().unwrap();
    }

    println!("所有任务执行完成,总耗时:{:?}", start_time.elapsed());
}

和Go的实现思路一致,每个线程中创建的Python子进程都是独立的,拥有自己的GIL,所以多个脚本可以同时执行,实现真正的并行。

优化建议

  • 如果Python脚本执行频率很高,频繁创建进程会有开销,可以考虑预先启动固定数量的Python进程,用进程池或者消息队列的方式分发任务,减少进程创建销毁的成本。
  • 如果需要传递复杂数据,可以用共享文件、Redis、消息队列等方式在Go/Rust主程序和Python脚本之间传递,避免直接通过标准输入输出传递大量数据导致阻塞。
  • 注意Python环境的隔离,如果不同的脚本需要不同的依赖,可以用虚拟环境或者容器的方式隔离每个Python进程的运行环境,避免依赖冲突。

总结

利用Go或Rust调用Python脚本实现真正并行的核心,是规避Python GIL的限制,通过创建独立的Python进程让每个脚本实例拥有自己的运行环境。Go可以结合协程和exec.Command实现,Rust可以结合线程和std::process::Command实现,两者本质都是利用操作系统的进程隔离能力,让多个Python任务真正并行执行,充分利用多核CPU的性能。

GoRustPython脚本调用并行执行多进程修改时间:2026-05-28 21:16:32

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。