英文:
How to identify the stack size of goroutine?
问题
我知道Go协程可以有一些阻塞操作,想知道一个Go协程是否可以像普通函数一样调用用户定义的阻塞函数。一个用户定义的阻塞函数有几个步骤,比如步骤1、步骤2。
换句话说,我想找出在Go协程中是否可以有嵌套的阻塞调用。
更新:
最初的意图是找出Goroutine使用的堆栈大小,特别是在有嵌套的阻塞调用时。对于答案和评论的帮助,我创建了以下函数,其中包含100,000个Goroutine,它在我的Ubuntu桌面上占用了782MB的虚拟内存和416MB的常驻内存。这相当于每个Go协程堆栈使用78KB的内存。这个说法正确吗?
package main
import (
"fmt"
"time"
)
func f(a int) {
x := f1(a)
f2(x)
}
func f1(a int) int {
r := step("1a", a)
r = step("1b", r)
return 1000 * a
}
func f2(a int) {
r := step("2a", a)
r = step("2b", r)
}
func step(a string, b int) int {
fmt.Printf("%s %d\n", a, b)
time.Sleep(1000 * time.Second)
return 10 * b
}
func main() {
for i := 0; i < 100000; i++ {
go f(i)
}
//go f(20)
time.Sleep(1000 * time.Second)
}
英文:
I know go routine can have a few blocking actions, wonder if a goroutine can call a user-defined blocking function like a regular function. A user-defined blocking function has a few steps like, step1, step2.
In another word, I would like to find out whether we can have nested blocking calls in a go routine.
UPDATE:
Original intention was to find the stack size used by goroutine, especially with nested blocking calls. Sorry for the confusion. Thanks to the answer and comments, I created the following function that has 100,000 goroutines, it took 782MB of virtual memory and 416MB of Resident memory on my Ubuntu desktop. It evens out to be 78KB of memory for each go routine stack. Is this a correct statement?
package main
import (
"fmt"
"time"
)
func f(a int) {
x := f1(a);
f2(x);
}
func f1(a int) int {
r := step("1a", a);
r = step("1b", r);
return 1000 * a;
}
func f2(a int) {
r := step("2a", a);
r = step("2b", r);
}
func step(a string, b int) int{
fmt.Printf("%s %d\n", a, b);
time.Sleep(1000 * time.Second)
return 10 * b;
}
func main() {
for i := 0; i < 100000; i++ {
go f(i);
}
//go f(20);
time.Sleep(1000 * time.Second)
}
答案1
得分: 4
我相信你是对的,尽管我不确定"virtual"和"resident"内存之间的关系,但可能存在一些重叠。
需要考虑的一些事情:你运行的是10万次,而不是1万次。
栈本身可能包含用于printf、方法参数等的字符串。
截至go 1.2,默认的栈大小(每个go例程)为8KB,这可能解释了其中一部分。
从go 1.3开始,它还使用指数增长的栈大小,但我怀疑这不是你遇到的问题。
英文:
I believe you're right, though I'm unsure of the relationship between "virtual" and "resident" memory it's possible there's some overlap.
Some things to consider: you're running 100,000 it appears, not 10,000.
The stack itself might contain things like the strings used for the printfs, method parameters, etc.
As of go 1.2 the default stack size (per go routine) is 8KB which may explain some of it.
As of go 1.3 it also uses an exponentially increasing stack size, but I doubt that's the problem you're running into.
答案2
得分: 0
简短回答是的。
一个goroutine是一个“轻量级线程”,这意味着它可以独立于程序中的其他代码执行任务。它几乎就像启动了一个新的程序,但你可以使用golang提供的构造来与其他代码进行通信(通道、锁等)。
附注:一旦主函数结束,所有的goroutine都会被终止(这就是为什么在示例中需要time.Sleep())。
以下是一个简单的示例(在golang playground中无法运行,因为有限制):
package main
import (
"fmt"
"time"
)
func saySomething(a, b func()){
a()
b()
}
func foo() {
fmt.Println("foo")
}
func bar() {
fmt.Println("bar")
}
func talkForAWhile() {
for {
saySomething(foo, bar)
}
}
func main() {
go talkForAWhile()
time.Sleep(1 * time.Second)
}
英文:
Short answer yes.
A goroutine is a "lightweight thread", that means it can do stuff independently from other code in your program. It's almost as if you started a new program, but you can communicate with your other code using the constructs golang provides (channels, locks, etc.).
P.S. Once the main function ends, all goroutines are killed (that's why you need the time.Sleep() in the example)
Here's the quick example (won't run in the golang playground because of their constraints):
package main
import (
"fmt"
"time"
)
func saySomething(a, b func()){
a()
b()
}
func foo() {
fmt.Println("foo")
}
func bar() {
fmt.Println("bar")
}
func talkForAWhile() {
for {
saySomething(foo, bar)
}
}
func main() {
go talkForAWhile()
time.Sleep(1 * time.Second)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论