我知道goroutine被多路复用到多个OS线程上,因此如果应该阻塞,例如在等待I/O时,其他人继续运行.但有没有办法提前知道如果我要创建n个goroutines我会产生多少个线程?
例如,如果我们调用下面的函数,我们就知道将为n个goroutines创建多少(或最大数量)系统线程:
type Vector []float64
// Apply the operation to n elements of v starting at i.
func (v Vector) DoSome(i, n int, u Vector, c chan int) {
for ; i < n; i++ {
v[i] += u.Op(v[i])
}
c <- 1; // signal that this piece is done
}
Run Code Online (Sandbox Code Playgroud) 作为一个愚蠢的基本线程练习,我一直在尝试在golang中实现睡眠理发师问题.有了频道,这应该很容易,但我遇到了一个heisenbug.也就是说,当我尝试诊断它时,问题就消失了!
考虑以下.该main()函数将整数(或"客户")推送到shop通道上.barber()读取shop频道以削减"顾客"的头发.如果我fmt.Print在customer()函数中插入一个语句,程序将按预期运行.否则,barber()永远不要削减任何人的头发.
package main
import "fmt"
func customer(id int, shop chan<- int) {
// Enter shop if seats available, otherwise leave
// fmt.Println("Uncomment this line and the program works")
if len(shop) < cap(shop) {
shop <- id
}
}
func barber(shop <-chan int) {
// Cut hair of anyone who enters the shop
for {
fmt.Println("Barber cuts hair of customer", <-shop)
}
}
func …Run Code Online (Sandbox Code Playgroud) 我有一些频道都收到相同的消息:
func broadcast(c <-chan string, chans []chan<- string) {
for msg := range c {
for _, ch := range chans {
ch <- msg
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是,由于每个通道chans都可能以不同的速率读取,因此当我得到一个慢的消费者时,我不想阻止其他通道.我用goroutines解决了这个问题:
func broadcast(c <-chan string, chans []chan<- string) {
for msg := range c {
for _, ch := range chans {
go func() { ch <- msg }()
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是,传递给每个通道的消息顺序很重要.我看了一下规范,看看频道在封锁时是否保留了顺序,而我发现的只是:
如果容量大于零,则通道是异步的:如果缓冲区未满(发送)或非空(接收),则通信操作成功而不阻塞,并且按发送顺序接收元素.
对我来说,如果写入被阻止,那么它不会被"发送",而是等待被发送.有了这个假设,上面没有说明多个goroutine在写入时被阻止的发送顺序.
在通道被解除阻塞后,是否有关于发送顺序的保证?
我以为我找到了一种简单的方法来立即返回http响应,然后在后台进行一些工作而不会阻塞.但是,这不起作用.
func MyHandler(w http.ResponseWriter, r *http.Request) {
//handle form values
go doSomeBackgroundWork() // this will take 2 or 3 seconds
w.WriteHeader(http.StatusOK)
}
Run Code Online (Sandbox Code Playgroud)
它第一次工作 - 立即返回响应并开始后台工作.但是,任何进一步的请求都会挂起,直到后台goroutine完成.有没有更好的方法来执行此操作,这不涉及设置消息队列和单独的后台进程.
在Go中防止种族状况有哪些好的做法?
我能想到的唯一一个就是不在goroutine之间共享数据 - 父goroutine发送一个对象的深层副本而不是对象本身,所以child goroutine不能改变父对象的内容.这将消耗更多的堆内存,但另一种方法是学习Haskell:P
编辑:同样,是否有任何情况我上面描述的方法仍然可以遇到竞争条件?
我有一个非常简单算法的研究计划.当成功来临时,goroutine应该通过os.Exit(0)关闭(结束).我等了一天,两天......什么?:)
这是简单的代码
package main
import "os"
func main() {
for {
go func() { os.Exit(0) }()
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:
来自:http : //blog.nindalf.com/how-goroutines-work/
由于goroutine是协同调度的,因此不断循环的goroutine会使同一线程上的其他goroutine饿死。
Goroutine很便宜,并且如果被阻塞,不会导致对其进行复用的线程阻塞
- 网络输入
- 睡眠
- 渠道运营或
- 阻止同步包中的原语。
因此,根据上述内容,假设您有类似这样的代码,除了循环随机次数并打印总和之外,什么也不做:
func sum(x int) {
sum := 0
for i := 0; i < x; i++ {
sum += i
}
fmt.Println(sum)
}
Run Code Online (Sandbox Code Playgroud)
如果您使用goroutines之类的
go sum(100)
go sum(200)
go sum(300)
go sum(400)
Run Code Online (Sandbox Code Playgroud)
如果只有一个线程,goroutine将一一运行吗?
我试图理解一个简单的Golang例程代码:
package main
import (
"fmt"
"time"
)
func sleep(seconds int, endSignal chan<- bool) {
time.Sleep(time.Duration(seconds) * time.Second)
endSignal <- true
}
func main() {
endSignal := make(chan bool, 1)
go sleep(3, endSignal)
var end bool
for !end {
select {
case end = <-endSignal:
fmt.Println("The end!")
case <-time.After(5 * time.Second):
fmt.Println("There's no more time to this. Exiting!")
end = true
}
}
}
Run Code Online (Sandbox Code Playgroud)
这很好,但为什么我不能在这个"选择"块中使用简单的默认值?像这样的东西:
for !end {
select {
case end = <-endSignal:
fmt.Println("The end.")
case <-time.After(4 * time.Second): …Run Code Online (Sandbox Code Playgroud) 我是Go的新手.假设我有一台服务器正在侦听HTTP请求,同时我需要检查Redis通知,以便我可以更新数据.以下是一个例子:
func checkExpire() {
for {
switch msg := pubSubConn.Receive().(type) {
case redis.Message:
...
}
}
server.ListenAndServe()
Run Code Online (Sandbox Code Playgroud)
简单地将checkExpiregoroutine 放入一个好的解决方案吗?
go func() {
for {
switch msg := pubSubConn.Receive().(type) {
case redis.Message:
...
}
}()
Run Code Online (Sandbox Code Playgroud) func getRecords(ctx context.Context, ids *[]Id) error {
ctx, cancel := context.WithTimeout(ctx, DefaultTimeout)
defer cancel()
var wg sync.WaitGroup
size := len(*ids)
allErrors := make(chan error, size)
for i := 0; i < size; i++ {
wg.Add(1)
go func(x int){
err := //call to other func which return error type. nil or error
if err != nil { // I will be creating n goroutines. How to exit rightaway if one of
// them return error
allErrors <- err
}
wg.Done()
}(i) …Run Code Online (Sandbox Code Playgroud)