有没有办法检测 go 例程在执行时是否被中断?我想要类似于InterruptedExceptionJava的东西: https ://docs.oracle.com/javase/8/docs/api/java/lang/InterruptedException.html
我这里有一个 go 例程,需要在上下文过期时从外部 go 例程中停止。然而,当上下文过期时,go 例程不会停止,即使控制它的 go 例程停止,它也会继续运行。
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctxParent := context.Background()
ch := make(chan bool)
d := 5 * time.Second
ctx, cancel := context.WithTimeout(ctxParent, d)
defer cancel()
go doSomething(ctx, ch)
// go func() {
select {
// done
case _ = <-ch:
fmt.Println("goroutine finished")
}
fmt.Println("waiting 11 seconds on main thread, ending all go routines")
time.Sleep(11 * time.Second)
fmt.Println(">>>> END")
}
func doSomething(ctx context.Context, ch chan<- bool) {
// …Run Code Online (Sandbox Code Playgroud) 关于 int 类型上 Go 数据竞争的问题。当我运行下面的程序时go run -race main.go,
package main
import "fmt"
var i int
func main() {
go func() {
i = 10
}()
i = 5
fmt.Println(i)
}
Run Code Online (Sandbox Code Playgroud)
它显示数据竞争警告。
~ $ go run -race main.go
5
==================
WARNING: DATA RACE
Write at 0x000000605908 by goroutine 7:
main.main.func1()
/home/dty1er/main.go:80 +0x3a
Previous write at 0x000000605908 by main goroutine:
main.main()
/home/dty1er/main.go:83 +0x56
Goroutine 7 (running) created at:
main.main()
/home/dty1er/main.go:79 +0x46
==================
Found 1 data race(s)
exit status 66
Run Code Online (Sandbox Code Playgroud)
我知道为什么会发生这种数据竞争; …
我正在使用 Go 中的 RWMutex 进行实验,我意识到可以使用以下代码实现这种行为:
package main
import (
"fmt"
"sync"
"time"
)
type RLockAndLockStruct struct {
mu sync.RWMutex
mapEx map[string]string
}
func main() {
r := &RLockAndLockStruct{}
r.mapEx = make(map[string]string)
go r.RLockAndLockTest("test", "goroutine 1 - ")
go r.RLockAndLockTest("test", "goroutine 2 - ")
time.Sleep(4000 * time.Millisecond)
}
func …Run Code Online (Sandbox Code Playgroud) 我有一个 golang API 端点及其关联的上下文。
端点需要在幕后执行一些繁重的工作,因此我在主端点内创建一个新的子例程,然后返回响应本身。
为了处理上下文取消,我创建了一个后台上下文并将其作为新上下文传递给子例程。
问题是通过这样做,是的,我可以执行后台子例程,但是主上下文中用于跟踪的值,如请求 id、span id 等(大多数键对我来说是未知的)将是丢失的。
即使在响应发送到客户端之后,如何将父上下文传递给子例程而不取消执行。
我没有将任何值传递到上下文中。但最初我们传递的是跟踪所需的 request-id、span-id 等。这些信息都在上下文中。这是一个内部库,上下文是我们保存它的地方。
我知道这是使用上下文传递值的反模式,除了请求 ID 和其他对库而不是业务逻辑重要的值之外,不会传递任何值
我的程序是这样的:
func handle(conn net.Conn) {
msg := "hello, world!"
for i:= 0; i< 100000; i++ {
go func() {
err := write(conn, msg)
}
}
}
func write(conn net.Conn, msg string) error {
mlen := fmt.Sprintf("%04d", len(msg))
_, err := conn.Write([]byte(mlen + msg))
return err
}
Run Code Online (Sandbox Code Playgroud)
程序会同时运行100000个goroutine,所有的goroutine都会向同一个连接发送消息?我怀疑服务器会收到“hellohelloworldworld”之类的错误消息,但是在我的 Ubuntu 14.04LTS 中运行程序时没有问题。
那么,多个 goroutine 会同时调用 Conn 上的一个方法吗?
================================================== ========================
我怎样才能保持Write方法的原子性?
我目前正在盯着以下代码的增强版本:
func embarrassing(data []string) []string {
resultChan := make(chan string)
var waitGroup sync.WaitGroup
for _, item := range data {
waitGroup.Add(1)
go func(item string) {
defer waitGroup.Done()
resultChan <- doWork(item)
}(item)
}
go func() {
waitGroup.Wait()
close(resultChan)
}()
var results []string
for result := range resultChan {
results = append(results, result)
}
return results
}
Run Code Online (Sandbox Code Playgroud)
这只是在想我的想法.所有这一切都可以用其他语言表达为
results = parallelMap(data, doWork)
Run Code Online (Sandbox Code Playgroud)
即使在Go中不能轻易做到这一点,是不是还有比上面更好的方法呢?
这里对Golang来说很新,并且在使用goroutines进行基准测试时遇到了问题.
我的代码在这里:
type store struct{}
func (n *store) WriteSpan(span interface{}) error {
return nil
}
func smallTest(times int, b *testing.B) {
writer := store{}
var wg sync.WaitGroup
numGoroutines := times
wg.Add(numGoroutines)
b.ResetTimer()
b.ReportAllocs()
for n := 0; n < numGoroutines; n++ {
go func() {
writer.WriteSpan(nil)
wg.Done()
}()
}
wg.Wait()
}
func BenchmarkTest1(b *testing.B) {
smallTest(1000000, b)
}
func BenchmarkTest2(b *testing.B) {
smallTest(10000000, b)
}
Run Code Online (Sandbox Code Playgroud)
它看起来两个场景的运行时和分配应该是相似的,但运行它们会给我以下结果,这些结果有很大的不同.不知道为什么会这样?那些额外的分配来自哪里?
BenchmarkTest1-12 1000000000 0.26 ns/op 0 B/op 0 allocs/op
BenchmarkTest2-12 1 2868129398 ns/op 31872 B/op …
以下代码记录了一个错误:
致命错误:所有goroutine都在睡着-死锁!
package main
import "fmt"
func main() {
ch := make(chan int)
ch <- 1
fmt.Println(<-ch)
}
Run Code Online (Sandbox Code Playgroud)
但是,当我将代码更改为:
package main
import "fmt"
func assign (ch chan int) {
ch <- 1
}
func main() {
ch := make(chan int)
go assign (ch)
fmt.Println(<-ch)
}
Run Code Online (Sandbox Code Playgroud)
打印出“ 1”。
然后我使用了缓冲通道:
package main
import "fmt"
func main() {
ch := make(chan int, 2)
ch <- 1
ch <- 2
fmt.Println(<-ch)
fmt.Println(<-ch)
}
Run Code Online (Sandbox Code Playgroud)
也可以打印“ 1”和“ 2”。
我对此情况有些困惑。提前致谢!
考虑以下来自go 之旅的示例。
如何确定频道的接收顺序?为什么 x 总是从 gorouting 获得第一个输出?这听起来很合理,但我没有找到任何关于它的文档。我尝试添加一些睡眠,但仍然从第一次执行的 gorouting 中获取输入。
c := make(chan int)
go sumSleep(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y)
Run Code Online (Sandbox Code Playgroud)
睡眠是在发送到通道之前。
go ×10
goroutine ×10
channel ×3
concurrency ×3
benchmarking ×1
interrupt ×1
memory-leaks ×1
networking ×1