英文:
Is map[string] chan thread safe?
问题
感谢您在这个问题上的帮助。
据我所知,在Go语言中,map
是非线程安全的,而chan
是线程安全的。但是,如果我将chan
用作map
的值,那么这个map
会变得线程安全吗?
我编写了一个简单的测试(不确定这是否是证明的正确方式),如下所示,并且运行了大约30次,没有出现"concurrent map read/write error"。这是否意味着线程安全的chan
使得非线程安全的map
变得线程安全了?
无论map
是否变得线程安全,有人能否对此进行更深入的解释?谢谢!
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().Unix())
te := &testS{
name: "test",
val: map[string]chan int{
"a": make(chan int, 10000000),
},
}
for i := 0; i < 50000; i++ {
te.val["a"] <- i
}
for i := 0; i < 30000; i++ {
go write(te)
go read(te)
}
for {
fmt.Println("Waiting")
time.Sleep(time.Second)
}
}
func read(t *testS) {
time.Sleep(time.Duration(rand.Intn(3)) * time.Second)
<-t.val["a"]
fmt.Println("read")
}
func write(t *testS) {
time.Sleep(time.Duration(rand.Intn(3)) * time.Second)
t.val["a"] <- 1
fmt.Println("write")
}
type testS struct {
name string
val map[string]chan int
}
英文:
thanks for helping me in this question.
To my acknowledge, in golang map
is non-thread-safe but chan
is thread-safe.But what if i use chan
as map
's value? Will this map
become thread safe?
I write a simple test(don't know if this is the currect way to prove) as shown below, and run it for about 30 times without concurrent map read/write error
.Does this means thread-safe chan
makes the non-thread-safe map
thread-safe?
Whether the map
become thread safe, can anyone explain this a little bit deeper for me?Thanks!
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().Unix())
te := &testS{
name: "test",
val: map[string]chan int{
"a": make(chan int, 10000000),
},
}
for i := 0; i < 50000; i++ {
te.val["a"] <- i
}
for i := 0; i < 30000; i++ {
go write(te)
go read(te)
}
for {
fmt.Println("Waiting")
time.Sleep(time.Second)
}
}
func read(t *testS) {
time.Sleep(time.Duration(rand.Intn(3)) * time.Second)
<-t.val["a"]
fmt.Println("read")
}
func write(t *testS) {
time.Sleep(time.Duration(rand.Intn(3)) * time.Second)
t.val["a"] <- 1
fmt.Println("write")
}
type testS struct {
name string
val map[string]chan int
}
答案1
得分: 1
我认为我解决了这个问题。
正如@mkopriva所说,这个例子实际上从未写入map
。但是这个例子也可以帮助我理解这个问题:
对chan
的读取/写入实际上不会影响map
,你可以将map
视为存储通道地址的地方,只有在删除或添加map
中的内容时才会对其进行写入。对chan
的读取/写入不会影响其地址,因此不会对map
进行"写入"。
简而言之:对chan
的读取/写入与对map
的读取/写入无关。
我还有另一个测试来证明这一点:
test := map[string]chan int{
"a": make(chan int, 1000),
}
for i := 0; i < 200; i++ {
test["a"] <- i
}
go func() {
for {
fmt.Printf("从chan中获取:%d\n", <-test["a"])
time.Sleep(time.Second)
}
}()
time.Sleep(5 * time.Second)
newChan := make(chan int, 1000)
for i := 200; i > 0; i-- {
newChan <- i
}
test["a"] = newChan
for {
fmt.Println("等待中")
time.Sleep(time.Second)
}
你会发现,在将test["a"]
更改为newChan
之后,输出将开始打印newChan
中的元素。
英文:
I think i got this question sovled.
As @mkopriva says, this example actually never write to the map
. But this example can also helps me understanding this question:
Read/Writing to the chan
acutually doesn't affect the map
, you can think the map
is storaging the channel's address, only if you delete or add something to the map
will you write to it. Reading/Writing to the `chann`` doesn't affect its address, so won't "write" to the map.
In one word: Reading/Writing the chan
is not related to reading/writing the map
Also i have another test for prove it:
test := map[string]chan int{
"a": make(chan int, 1000),
}
for i := 0; i < 200; i++ {
test["a"] <- i
}
go func() {
for {
fmt.Printf("get from chan: %d\n", <-test["a"])
time.Sleep(time.Second)
}
}()
time.Sleep(5 * time.Second)
newChan := make(chan int, 1000)
for i := 200; i > 0; i-- {
newChan <- i
}
test["a"] = newChan
for {
fmt.Println("waiting")
time.Sleep(time.Second)
}
You will see that after changing test["a"]
to newChan
, the output will start print the element in newChan
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论