Why Switch from PHP to Go? Boosting Live‑Streaming Concurrency

The article explains why a backend developer moved from PHP to Go, highlights Go’s popularity and simplicity, and demonstrates how Go’s concurrency primitives like sync.WaitGroup and errgroup can transform serial live‑stream data fetching into parallel execution, drastically reducing request latency.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
Why Switch from PHP to Go? Boosting Live‑Streaming Concurrency

1. Reasons to Choose Go

As a backend developer, the author compares PHP and Go, noting PHP's ease of use but its inability to handle high‑concurrency workloads such as live‑streaming services. Go is popular among large tech companies, simple to pick up, and better suited for concurrent tasks.

2. How Go Solves Concurrency

In a typical PHP implementation, fetching multiple pieces of information for a live room (version service, basic live info, user info, equity info, statistics) is done serially, causing the total request time to equal the sum of all operations. With Go, the request time is reduced to the longest single operation because the tasks run in parallel.

Implementation using sync.WaitGroup :

//请求入口
func main() {
    var (
        VersionDetail, LiveDetail, UserDetail, EquityDetail, StatisticsDetail int
    )
    ctx := context.Background()
    GoNoErr(ctx, func() {
        VersionDetail = 1 //版本服务信息
        time.Sleep(1 * time.Second)
        fmt.Println("执行第一个任务")
    }, func() {
        LiveDetail = 2 //直播基础信息
        time.Sleep(2 * time.Second)
        fmt.Println("执行第二个任务")
    }, func() {
        UserDetail = 3 //用户信息
        time.Sleep(3 * time.Second)
        fmt.Println("执行第三个任务")
    }, func() {
        EquityDetail = 4 //直播关联权益信息
        time.Sleep(4 * time.Second)
        fmt.Println("执行第四个任务")
    }, func() {
        StatisticsDetail = 5 //直播间信息统计
        time.Sleep(5 * time.Second)
        fmt.Println("执行第五个任务")
    })
    fmt.Println(VersionDetail, LiveDetail, UserDetail, EquityDetail, StatisticsDetail)
}

//并发方法
func GoNoErr(ctx context.Context, functions ...func()) {
    var wg sync.WaitGroup
    for _, f := range functions {
        wg.Add(1)
        // 每个函数启动一个协程
        go func(function func()) {
            function()
            wg.Done()
        }(f)
    }
    // 等待执行完
    wg.Wait()
}

Implementation using errgroup :

//请求入口
func main() {
    var (
        VersionDetail, LiveDetail, UserDetail, EquityDetail, StatisticsDetail int
        err                                                                   error
    )
    ctx := context.Background()
    err = GoErr(ctx, func() error {
        VersionDetail = 1 //版本服务信息
        time.Sleep(1 * time.Second)
        fmt.Println("执行第一个任务")
        return nil //返回实际执行的错误
    }, func() error {
        LiveDetail = 2 //直播基础信息
        time.Sleep(2 * time.Second)
        fmt.Println("执行第二个任务")
        return nil //返回实际执行的错误
    }, func() error {
        UserDetail = 3 //用户信息
        time.Sleep(3 * time.Second)
        fmt.Println("执行第三个任务")
        return nil //返回实际执行的错误
    }, func() error {
        EquityDetail = 4 //直播关联权益信息
        time.Sleep(4 * time.Second)
        fmt.Println("执行第四个任务")
        return nil //返回实际执行的错误
    }, func() error {
        StatisticsDetail = 5 //直播间信息统计
        time.Sleep(5 * time.Second)
        fmt.Println("执行第五个任务")
        return nil //返回实际执行的错误
    })
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(VersionDetail, LiveDetail, UserDetail, EquityDetail, StatisticsDetail)
}

func GoErr(ctx context.Context, functions ...func() error) error {
    var eg errgroup.Group
    for i := range functions {
        f := functions[i]  //请注意这里的写法,下面有讲解
        eg.Go(func() (err error) {
            err = f()
            if err != nil {
                //记日志
            }
            return err
        })
    }
    // 等待执行完
    return eg.Wait()
}

Common closure‑capture pitfall in Go loops and three ways to write the loop correctly:

for i := range functions {
    f := functions[i]
    eg.Go(func() (err error) {
        err = f()
for _, f := range functions {
    fs := f
    eg.Go(func() (err error) {
        err = fs()
for _, f := range functions {
    eg.Go(func() (err error) {
        err = f()

The third version captures the loop variable directly, leading to all goroutines using the same final value, which produces incorrect results (shown in the image below).

The expected correct output is shown in the next image.

Key takeaway: using sync.WaitGroup or errgroup to split a parent task into multiple child tasks greatly improves concurrency and reduces execution time; both patterns are practical and widely used in Go projects.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

backend-developmentconcurrencyGoerrgroupWaitGroup
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.