我相信和很多使用golang的朋友一样,开始接触并学习go语言都是被其优秀的并发能力所吸引。比如我需要从一个目录中,筛选符合要求的(比如时间符合)日志,然后从其中提取一些数据。就可以以下面的方式:
package main
import (
"fmt"
"time"
)
func worker(task_id int, filepath string, w io.Writer) {
... 处理 filepath 的文件
... 将处理结果写入w中(golang中高度抽象的io.Writer 和io.Reader非常便于将)
// 或将结果传入管道 ch <- fmt.Sprintf("%d,%s", task_id, res)
}
func main() {
input := [...]string{}
start := time.Now()
... 获取某个目录下的所有文件,然后做合法性判断,并将它们存入上面的数组中
for i, filepath := range input {
go worker(i, filepath, w)
}
// 或创建一个管道 chan := make(chan string)
// 将处理结果在worker 中传入管道,然后在这里遍历管道取出
// for range chan_name { fmt.Println(<- ch) }
end := time.Now()
fmt.Printf("Job Finished,Spent %s Secs On Processing", end.Sub(start))
}
golang中的管道,就是用于go协程之间的内存共享的具体实现。这样就完成了一个最基础的并发应用。我之前是使用pypy运行python脚本完成相同的工作,几十个日志文件也需要耗费若干分钟的时间。而使用golang,只需要花费数十秒。
当然这样实现是不妥当的,这样会同时创建若干个go协程,同时开始工作。而由于go语言本身设置,如果不在代码中设置使用的cpu数量,那么就会利用所有核心,瞬间导致系统IO负载暴增。并且,如果我们有这样的需求——要求任务结果能按照任务传入管道的顺序输出。那么目前这种代码显然是无法满足我们的需求的。