map[string] chan是否是线程安全的?

huangapple go评论81阅读模式
英文:

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 (
	&quot;fmt&quot;
	&quot;math/rand&quot;
	&quot;time&quot;
)

func main() {
	rand.Seed(time.Now().Unix())
	te := &amp;testS{
		name: &quot;test&quot;,
		val: map[string]chan int{
			&quot;a&quot;: make(chan int, 10000000),
		},
	}

	for i := 0; i &lt; 50000; i++ {
		te.val[&quot;a&quot;] &lt;- i
	}

	for i := 0; i &lt; 30000; i++ {
		go write(te)
		go read(te)
	}
	for {
		fmt.Println(&quot;Waiting&quot;)
		time.Sleep(time.Second)
	}
}

func read(t *testS) {
	time.Sleep(time.Duration(rand.Intn(3)) * time.Second)
	&lt;-t.val[&quot;a&quot;]
	fmt.Println(&quot;read&quot;)
}

func write(t *testS) {
	time.Sleep(time.Duration(rand.Intn(3)) * time.Second)
	t.val[&quot;a&quot;] &lt;- 1
	fmt.Println(&quot;write&quot;)
}

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{
		&quot;a&quot;: make(chan int, 1000),
	}

	for i := 0; i &lt; 200; i++ {
		test[&quot;a&quot;] &lt;- i
	}

	go func() {
		for {
			fmt.Printf(&quot;get from chan: %d\n&quot;, &lt;-test[&quot;a&quot;])
			time.Sleep(time.Second)
		}
	}()

	time.Sleep(5 * time.Second)
	newChan := make(chan int, 1000)
	for i := 200; i &gt; 0; i-- {
		newChan &lt;- i
	}
	test[&quot;a&quot;] = newChan
	for {
		fmt.Println(&quot;waiting&quot;)
		time.Sleep(time.Second)
	}

You will see that after changing test[&quot;a&quot;] to newChan, the output will start print the element in newChan

huangapple
  • 本文由 发表于 2021年12月21日 11:56:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/70430512.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定