我很好奇Go语言如何安排goroutines.它是仅在通道请求和I/O期间切换还是具有周期性协程切换循环?
我有一个昂贵的功能,我应用于切片的所有项目.我正在使用goroutines来处理它,每个goroutine处理切片的一个项目.
func Huge(lst []foo) {
for _, item := range lst {
go performSlow(item)
}
// How do I synchronize here ?
return someValue(lst)
}
Run Code Online (Sandbox Code Playgroud)
问题是,如评论所示,在调用someValue函数之前,等待所有goroutine完成工作的首选方法是什么?传递一个频道performSlow并等到每个人都写到它的工作,但它似乎有点过分:
func Huge(lst []foo) {
ch := make(chan bool)
for _, item := range lst {
go performSlow(item, ch) // performSlow does its job, then writes a dummy value to ch
}
for i := range lst {
_ = <-ch
}
return someValue(lst)
}
Run Code Online (Sandbox Code Playgroud)
是否有更好的(即更有效和/或更惯用)的方式来做到这一点?
我正在关注Go Tour,当涉及到goroutines时我有点卡住了.我知道他们非常轻量级,每次goroutine阻止,另一个将开始,但我无法理解这个例子实际如何工作:
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(1000 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
}
Run Code Online (Sandbox Code Playgroud)
据我所知,一个goroutine是针对具有参数"world"的say函数启动的,但据我所知,应该打印"world"五次并且"hello"一次.但是我不明白为什么输出是这样的:
hello
world
hello
world
hello
world
hello
world
hello
Run Code Online (Sandbox Code Playgroud)
从我对其他语言的线程的有限理解,输出应该是这样的:
hello
world
world
world
world
world
Run Code Online (Sandbox Code Playgroud)
或者像这样:
world
world
world
hello
world
world
Run Code Online (Sandbox Code Playgroud)
为什么第二行也执行五次?go语句下面的任何内容都会归类为go例程的一部分吗?
下一张幻灯片还显示了我无法再次回头看的内容:
package main
import "fmt"
func sum(a []int, c chan int) {
sum := 0 …Run Code Online (Sandbox Code Playgroud) 我有一个持续运行的Go程序,完全依赖于goroutines + 1 manager线程.主线程只调用goroutines然后休眠.
有内存泄漏.该程序使用越来越多的内存,直到它耗尽所有16GB RAM + 32GB SWAP,然后每个goroutine恐慌.它实际上是操作系统内存导致恐慌,通常恐慌是fork/exec ./anotherapp: cannot allocate memory我尝试执行时anotherapp.
发生这种情况时,所有工作线程都会发生混乱并恢复并重新启动.所以每个goroutine都会惊慌失措,恢复并重新启动......此时内存使用量不会减少,即使现在几乎没有任何分配,它仍然保持在48GB.这意味着所有goroutine总是会因为没有足够的内存而恐慌,直到整个可执行文件被杀死并完全重启.
整个事情大概是50,000行,但实际问题区域如下:
type queue struct {
identifier string
type bool
}
func main() {
// Set number of gorountines that can be run
var xthreads int32 = 10
var usedthreads int32
runtime.GOMAXPROCS(14)
ready := make(chan *queue, 5)
// Start the manager goroutine, which prepared identifiers in the background ready for processing, always with 5 waiting to go
go manager(ready)
// Start creating …Run Code Online (Sandbox Code Playgroud) 我一直在寻找周围,但到目前为止只进行了类似的文章写到这里通过Ariejan德弗鲁姆.
我想知道我是否可以将goroutine引入单元测试,以便它可以精确计算正在运行的goroutine的并发数量,并且可以告诉我它们是否正确地产生了我所说的数字goroutine.
我有以下代码例如..
import (
"testing"
"github.com/stretchr/testify/assert"
)
func createList(job int, done chan bool) {
time.Sleep(500)
// do something
time.Sleep(500)
done <- true
return
}
func TestNewList(t *testing.T) {
list := NewList()
if assert.NotNil(t, list) {
const numGoRoutines = 16
jobs := make(chan int, numGoRoutines)
done := make(chan bool, 1)
for j := 1; j <= numGoRoutines; j++ {
jobs <- j
go createList(j, done)
fmt.Println("sent job", j)
}
close(jobs)
fmt.Println("sent all jobs")
<-done
}
Run Code Online (Sandbox Code Playgroud) 我有一个在多个goroutine之间共享的Golang结构.对于结构成员的并发访问,有互斥锁sync.RWMutex.对于由单个goroutine访问的struct成员,是否需要互斥保护?
例如,在下面的代码中,一个单独的writer goroutine访问成员shared.exclusiveCounter,没有任何锁定保护.这是正确/安全吗?或者是否需要互斥锁,因为整个结构由多个goroutines通过共享指针访问?
package main
import (
"fmt"
"sync"
"time"
)
func main() {
s := &shared{mutex: &sync.RWMutex{}}
readerDone := make(chan int)
writerDone := make(chan int)
go reader(s, readerDone)
go writer(s, writerDone)
<-readerDone
<-writerDone
}
type shared struct {
mutex *sync.RWMutex
sharedCounter int // member shared between multiple goroutines, protected by mutex
exclusiveCounter int // member exclusive of one goroutine -- is mutex needed?
}
func (s *shared) readCounter() int {
defer s.mutex.RUnlock()
s.mutex.RLock()
return s.sharedCounter
}
func (s *shared) …Run Code Online (Sandbox Code Playgroud) 我刚开始看看go以及go的工作原理.我只是想知道你是否可以在C++中实现相同的东西并找到boost.fiber.goroutines和boost纤维有什么区别?你能用C++中的那些光纤实现goroutine吗?
这是我的程序产生死锁,我该如何避免它以及处理这种情况的推荐模式是什么.
问题是在超时后如何检测到我的频道上没有读卡器?
var wg sync.WaitGroup
func main() {
wg.Add(1)
c := make(chan int)
go readFromChannel(c, time.After(time.Duration(2)*time.Second))
time.Sleep(time.Duration(5) * time.Second)
c <- 10
wg.Wait()
}
func readFromChannel(c chan int, ti <-chan time.Time) {
select {
case x := <-c:
fmt.Println("Read", x)
case <-ti:
fmt.Println("TIMED OUT")
}
wg.Done()
}
Run Code Online (Sandbox Code Playgroud) 我正在寻找一种方法来异步执行go中的两个函数,它返回不同的结果和错误,等待它们完成并打印两个结果.另外,如果函数返回错误之一,我不想等待另一个函数,只打印错误.例如,我有这个功能:
func methodInt(error bool) (int, error) {
<-time.NewTimer(time.Millisecond * 100).C
if error {
return 0, errors.New("Some error")
} else {
return 1, nil
}
}
func methodString(error bool) (string, error) {
<-time.NewTimer(time.Millisecond * 120).C
if error {
return "", errors.New("Some error")
} else {
return "Some result", nil
}
}
Run Code Online (Sandbox Code Playgroud)
这里https://play.golang.org/p/-8StYapmlg就是我实现它的方式,但我认为它有太多的代码.它可以通过使用接口{}来简化,但我不想这样做.我想要更简单的东西,例如,可以使用async/await在C#中实现.可能有一些库可以简化这种操作.
更新:感谢您的回复!我得到多快帮助真是太棒了!我喜欢WaitGroup的用法.它显然使代码对更改更加健壮,因此我可以轻松地添加另一个异步方法,而不会最终改变方法的确切数量.但是,与C#相比,仍有如此多的代码.我知道在go中我不需要明确地将方法标记为异步,使它们实际上返回任务,但是方法调用看起来要简单得多,例如,考虑这个链接实际上也需要捕获异常 顺便说一下,我找到了在我的任务中,我实际上不需要知道我想要运行异步的函数的返回类型,因为无论如何它将被整理到json,现在我只是在go-kit的端点层调用多个服务.
正如我从 golang 文档中了解到的,如果我将 runtime.GOMAXPROCS(8) 设置为 8 核(intel i7)的 cpu,然后启动一个无限循环的 goroutine,其他 gorutines 不应该被阻塞,因为有足够的线程和 goprocs。但是在使用 net/http 包时就不是这样了,一个无限循环的 goroutine 会在几次调用后阻塞 http 服务器。任何人都可以帮助解释原因吗?
服务器代码:
package main
import (
"fmt"
"log"
"net/http"
"runtime"
)
func myHandler(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("hello"))
}
func infiniteloop() {
for {
}
}
func main() {
// set max procs for multi-thread executing
runtime.GOMAXPROCS(runtime.NumCPU())
// print GOMAXPROCS=8 on my computer
fmt.Println("GOMAXPROCS=", runtime.GOMAXPROCS(-1))
http.Handle("/", http.HandlerFunc(myHandler))
// uncomment …Run Code Online (Sandbox Code Playgroud) go ×10
goroutine ×10
concurrency ×4
block ×1
boost ×1
c++ ×1
channel ×1
http ×1
memory-leaks ×1
mutex ×1
tdd ×1
unit-testing ×1