Golang并发编程优化指南:如何加速程序运行

Golang并发编程优化指南:如何加速程序运行 你好,

我正在开发一个程序,它可能会进行大量的网络调用,我认为这可能会严重拖慢程序速度,甚至可能导致更糟的问题。最让我担心的代码是下面这段:

    for hostbuff.Scan() { //Buffer From File With Hostnames
        assetips, err := net.LookupIP(hostbuff.Text()) //Lookup IP And Put in Array
        // go assetips, err := net.LookupIP(hostbuff.Text()) //Would this work?
        if err != nil {
            fmt.Println("We had IP lookup error")
        }

    for _, ip := range assetips {
        //do stuff

我使用 net.LookupIP 来解析大量主机名以获取 IP 地址,并将它们放入一个数组中。然后,我会对这些 IP 地址执行不同类型的工作。我最担心的是 net.LookupIP 函数。是否有推荐的方法或思路来使其并发执行,例如使用 Goroutine 或其他方法?我首先想到的是直接写成 go assetips, err := net.LookupIP(hostbuff.Text()),但我担心这可能会引发问题。

提前感谢。


更多关于Golang并发编程优化指南:如何加速程序运行的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

好的,这里有几件事需要提一下,因为这是一个有趣的话题。基本上,只有当你在每个goroutine中启动所有调用,并且每个goroutine都有一个无限循环来执行调用并定期将数据收集到某个地方时,并发执行一些网络调用才值得。否则,如果网络调用太短,在goroutine中启动可能产生与串行执行相同的效果,因为可能会在其它goroutine开始之前就结束了第一个调用。

假设你处于第一种情况,最好要知道操作系统允许的文件描述符数量是有限的(例如,在Linux上是65535),如果你想进行超过此限制的更多网络调用,就必须增加这个限制。了解处理文件描述符、带宽和TCP僵尸连接是相当困难的事情,这是有好处的。

另一点是你收集数据的地方,简单且廉价的方法是使用映射(maps),但你必须注意锁的问题。

了解了这些之后,我认为你可以做到,但需要权衡在你的特定情况下,让事情并发执行是否值得。

更多关于Golang并发编程优化指南:如何加速程序运行的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


要加速这段代码,可以使用 Goroutine 和 Channel 实现并发 DNS 解析。以下是优化后的示例:

package main

import (
    "bufio"
    "fmt"
    "net"
    "sync"
)

func main() {
    // 假设 hostbuff 是从文件读取的 bufio.Scanner
    var hostbuff *bufio.Scanner
    
    // 创建带缓冲的 channel 用于传递结果
    resultChan := make(chan struct {
        host string
        ips  []net.IP
        err  error
    }, 100)
    
    // 创建 WaitGroup 等待所有 Goroutine 完成
    var wg sync.WaitGroup
    
    // 启动结果收集 Goroutine
    go func() {
        wg.Wait()
        close(resultChan)
    }()
    
    // 并发处理每个主机名
    for hostbuff.Scan() {
        host := hostbuff.Text()
        wg.Add(1)
        
        go func(h string) {
            defer wg.Done()
            
            ips, err := net.LookupIP(h)
            resultChan <- struct {
                host string
                ips  []net.IP
                err  error
            }{h, ips, err}
        }(host)
    }
    
    // 处理结果
    for result := range resultChan {
        if result.err != nil {
            fmt.Printf("Host %s: IP lookup error: %v\n", result.host, result.err)
            continue
        }
        
        for _, ip := range result.ips {
            // 对每个 IP 执行后续操作
            fmt.Printf("Host %s: IP %s\n", result.host, ip.String())
            // do stuff with ip
        }
    }
}

对于更精细的控制,可以使用 worker pool 模式限制并发数量:

func main() {
    var hostbuff *bufio.Scanner
    
    // 设置最大并发数
    maxWorkers := 50
    jobs := make(chan string, 100)
    results := make(chan struct {
        host string
        ips  []net.IP
        err  error
    }, 100)
    
    // 启动 worker pool
    var wg sync.WaitGroup
    for i := 0; i < maxWorkers; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for host := range jobs {
                ips, err := net.LookupIP(host)
                results <- struct {
                    host string
                    ips  []net.IP
                    err  error
                }{host, ips, err}
            }
        }()
    }
    
    // 发送任务
    go func() {
        for hostbuff.Scan() {
            jobs <- hostbuff.Text()
        }
        close(jobs)
    }()
    
    // 收集结果
    go func() {
        wg.Wait()
        close(results)
    }()
    
    // 处理结果
    for result := range results {
        if result.err != nil {
            fmt.Printf("Host %s: IP lookup error: %v\n", result.host, result.err)
            continue
        }
        
        for _, ip := range result.ips {
            // do stuff with ip
            fmt.Printf("Host %s: IP %s\n", result.host, ip.String())
        }
    }
}

关键优化点:

  1. 使用 Goroutine 并发执行 net.LookupIP 调用
  2. 通过 Channel 安全地传递结果
  3. 使用 sync.WaitGroup 确保所有 Goroutine 完成
  4. Worker pool 模式可以控制最大并发数,避免系统资源耗尽

直接使用 go assetips, err := net.LookupIP(hostbuff.Text()) 的问题在于:

  • 无法获取返回值
  • 无法控制并发数量
  • 可能导致 Goroutine 泄露
  • 错误处理困难
回到顶部