Go 去打进程的最大线程数?
我正在尝试Go做一些文件系统使用分析,我希望通过将几乎所有内容作为goroutine生成,并依靠Go VM(和GOMAXPROCS)来管理,从而尽可能快地生成代码。我一直看着这段代码运行(相当快),直到它死掉。我检查了top,它列出了我的进程有1500个线程 我想我可能已经达到了一些极限,因此在等待操作系统时进程陷入僵局。我检查了我的操作系统(FreeBSD)限制,果然它被列为每个进程最多1500个线程 令人惊讶的是,我检查了Go文档,它说GOMAXPROCS只是对运行线程的限制,但阻塞的线程不算在内 所以我的问题是:Go 去打进程的最大线程数?,go,Go,我正在尝试Go做一些文件系统使用分析,我希望通过将几乎所有内容作为goroutine生成,并依靠Go VM(和GOMAXPROCS)来管理,从而尽可能快地生成代码。我一直看着这段代码运行(相当快),直到它死掉。我检查了top,它列出了我的进程有1500个线程 我想我可能已经达到了一些极限,因此在等待操作系统时进程陷入僵局。我检查了我的操作系统(FreeBSD)限制,果然它被列为每个进程最多1500个线程 令人惊讶的是,我检查了Go文档,它说GOMAXPROCS只是对运行线程的限制,但阻塞的线程不
- 公平地说,我不能依靠GoVM作为一个全局池来防止达到这类操作系统的限制吗
- 有没有一个惯用的方法来处理这个问题(好一点,这只是我使用围棋的第二天)
- 特别是,我还没有找到一个很好的方法,除了同步关闭一个频道时,我使用它。有更好的办法吗
- 我想抽象出样板文件(使用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)
}
}
func分析路径(路径chan字符串)chan分析路径{
已分析:=生成(chan AnalyzedPath)
go func(){
组:=sync.WaitGroup{}
对于路径:=范围路径{
组。添加(1)
go func(路径字符串){
延迟组。完成()
分析大约2个月前(或更多)语言开发人员谈到线程计数控制的入侵(以及一些其他限制)。因此,我们可以期待很快看到它。一个多月前,我开发了这个问题,并在我的linux计算机上发现GOMAXPROCS的值不超过256。如果我向它发送300或更多,结果总是256。但我发现goroutines不是线程。goroutines可以存在于一个线程中
至于惯用的同步——我认为没有必要同步太多。
在我的代码中,我通常使用goroutine只通过通道进行通信的思想,通道应该作为goroutine的参数传递
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
}
func main(){
ch1:=制造(类型1)
ch2:=制造(类型2)
go发电机(ch1、ch2)
go处理器(ch1、ch2)
//在此,主func将一直等待,直到它捕获2个ch2完成信号
一些评论:a)没有Go虚拟机。有Go运行时,但这不是一个虚拟机或与之相近的东西。b)不,Go不是防止你滥用硬件的日托;实际上Go的级别很低,足以很好地使用你的硬件(但允许越界)。c)你说“通过生成几乎所有的goroutine尽可能快地生成代码”,这在我看来是有问题的:当然,您需要至少n个并发goroutine来保持n个处理器(核心)a)我们不要太迂腐,因为在这个问题上,虚拟机和运行时是可互换的,因为在我的代码和硬件之间有某种东西,可以为我管理它。b)现在你正在屈尊俯就……这是一种经常被吹捧为awesom的语言e对于并发性,智能资源管理在我看来并不是一个不合理的期望。c)Duh,但我不是在问为什么我没有获得更快的性能,我是在问我是否因为达到了操作系统的限制而陷入了死锁。a)不是迂腐:没有任何东西会在代码和硬件之间。操作系统和运行时更多地位于代码的一侧,而不是介于两者之间。b)和c)不会带来任何结果:你期望Go提供一些在任何情况下都无法提供的东西。@Volker,这是一种迂腐的行为,因为把VM换成运行时对我的问题没有影响。其次,Go有一个“调度器”"管理goroutines——对我来说,这确实表明,在goroutines方面,运行时并不是“坐在一边”。交付并非不可能。运行时可以检查是否存在操作系统限制,避免创建更多线程……它可以将GOMAXPROCS视为活动线程和阻塞线程,也可以添加GOMAXT线程选项。如果我遇到了我认为是的问题,上面的任何一项都很好,而且不是“不可能”。嗯,但是由于我的goroutines可能会无序执行,我不确定如何知道在不使用sync的情况下何时生成“weAreFinishedSignal”。如果我理解正确,您的示例不会显式地并行处理,但是可以产生n个处理器来实现并行化?嗯,这里有3个执行分支。主分支产生生成器分支和处理器分支,然后变得昏昏欲睡(我所做的等待信号是试图为我想要分析的每个路径生成一个新的goroutine,而这个设置是按每个处理器串行处理它们…如果我想要更多的并行化,我需要生成更多的处理器…但至少它设置了一个显式限制。