去处理最大线程?

时间:2013-11-27 00:39:16

标签: go

我正在尝试Go进行一些文件系统使用分析,我尽可能快地生成代码,将几乎所有内容都作为goroutine生成并依赖Go VM(和GOMAXPROCS)来管理它。我正在看这个代码运行(非常快)直到它刚刚停止。我检查了顶部,它将我的进程列为1500个线程。

我想也许我已经遇到了一些限制,因此这个过程在操作系统上等待死锁。我检查了我的操作系统(FreeBSD)限制,确定每个进程最多列出1500个线程。

很惊讶,我检查了Go文档,它说GOMAXPROCS只是运行线程的限制,但是阻塞的线程不计算在内。

所以我的问题:

  • 公平地说,我不能依赖Go VM作为全局池,以防止达到这些类型的操作系统限制吗?

  • 有没有一种惯用的方式来处理这个问题(很好,这只是我第二天使用Go)?

    • 特别是,当我使用它时,我没有找到除关闭频道以外的好方法。有更好的方法吗?

    • 我想抽象掉样板(用例程和并行映射) 完成时关闭通道),有没有类型安全的方法来做这个没有泛型?

这是我目前的代码:

func AnalyzePaths(paths chan string) chan AnalyzedPath {
    analyzed := make(chan AnalyzedPath)
    go func() {
        group := sync.WaitGroup{}
        for path := range paths {
            group.Add(1)
            go func(path string) {
                defer group.Done()
                analyzed <- Analyze(path)
            }(path)
        }
        group.Wait()
        close(analyzed)
    }()
    return analyzed
}

func GetPaths(roots []string) chan string {
    globbed := make(chan string)
    go func() {
        group := sync.WaitGroup{}
        for _, root := range roots {
            group.Add(1)
            go func(root string) {
                defer group.Done()
                for _, path := range glob(root) {
                    globbed <- path
                }
            }(root)
        }
        group.Wait()
        close(globbed)
    }()
    return globbed
}

func main() {
    paths := GetPaths(patterns)
    for analyzed := range AnalyzePaths(paths) {
        fmt.Println(analyzed)
    }
}

1 个答案:

答案 0 :(得分:3)

大约2个月前(或更多)语言开发人员谈到了线程计数控制(以及其他一些限制)的入侵。所以我们很快就能看到它。一个月或更久以前我开发问题,并在我的linux机器上发现GOMAXPROCS不超过256的值。如果我发送300或更多,结果总是256.但我发现goroutines不是一个线程。 Goroutines可以生活在一个线程中。

至于惯用同步 - 我认为没有必要同步太多。 在我的代码中,我通常使用goroutines仅通过通道进行通信的想法。并且通道应作为goroutines的参数传递。

func main() {
    ch1 := make(chan SomeType1)
    ch2 := make(chan SomeType2)
    go generator(ch1, ch2)
    go processor(ch1, ch2)
    // here main func becomes waiting until it capture 2 of ch2-finished-signals 
    <- ch2
    <- ch2
    // usually we don't need the exact values of ch2-signals,
    // so we assign it to nothing 
}

func generator(ch1 chan SomeType1, ch2 chan SomeType2) {
    for (YOUR_CONDITION){
        // generate something
        //....
        // send to channel
        ch1 <- someValueOfType1
    }
    ch1 <- magicStopValue
    ch2 <- weAreFinishedSignal1
}

func processor(ch1 chan SomeType1, ch2 chan SomeType2) {
    // "read" value from ch1 
    value := <-ch1
    for value != magicStopValue {
        // make some processing
        // ....
        //get next value from ch1 and replay processing
        value = <- ch1
    }
    // here we can send signal that goroutine2 is finished
    ch2 <- weAreFinishedSignal2
}

如果goroutines在一个线程中,则它们的通信速度更快。至于我,频道表现远非好,但足以达到很多目的。