英文:
Are golang net.UDPConn and net.TCPConn thread safe?? Can i read or write of single UDPConn object in multi thread?
问题
1.我们可以在同一个net.UDPConn或net.TCPConn对象上从一个线程调用send,从另一个线程调用recv吗?
2.我们可以在同一个net.UDPConn或net.TCPConn对象上从不同的线程并行调用多个send吗?
我找不到关于这个的好文档。
Golang的socket API是线程安全的吗?
我发现很难测试它是否是线程安全的。
对此有任何指导将会很有帮助。
我的测试代码如下:
package main
import (
"fmt"
"net"
"sync"
)
func udp_server() {
// 创建监听
conn, err := net.ListenUDP("udp", &net.UDPAddr{
IP: net.IPv4(0, 0, 0, 0),
Port: 8080,
})
if err != nil {
fmt.Println("监听失败", err)
return
}
defer conn.Close()
var wg sync.WaitGroup
for i := 0; i < 10; i = i + 1 {
wg.Add(1)
go func(socket *net.UDPConn) {
defer wg.Done()
for {
// 读取数据
data := make([]byte, 4096)
read, remoteAddr, err := socket.ReadFromUDP(data)
if err != nil {
fmt.Println("读取数据失败!", err)
continue
}
fmt.Println(read, remoteAddr)
fmt.Printf("%s\n\n", data)
// 发送数据
senddata := []byte("hello client!")
_, err = socket.WriteToUDP(senddata, remoteAddr)
if err != nil {
return
fmt.Println("发送数据失败!", err)
}
}
}(conn)
}
wg.Wait()
}
func main() {
udp_server()
}
这个测试代码可以吗?
英文:
1.Can we call send from one thread and recv from another on the same net.UDPConn or net.TCPConn objects?
2.Can we call multiple sends parallely from different threads on the same net.UDPConn or net.TCPConn objects?
I am unable to find a good documentation also for the same.
Is golang socket api thread safe?
I find that it is hard to test if it is thread safe.
Any pointers in the direction will be helpful.
My test code is below:
package main
import (
"fmt"
"net"
"sync"
)
func udp_server() {
// create listen
conn, err := net.ListenUDP("udp", &net.UDPAddr{
IP: net.IPv4(0, 0, 0, 0),
Port: 8080,
})
if err != nil {
fmt.Println("listen fail", err)
return
}
defer conn.Close()
var wg sync.WaitGroup
for i := 0; i < 10; i = i + 1 {
wg.Add(1)
go func(socket *net.UDPConn) {
defer wg.Done()
for {
// read data
data := make([]byte, 4096)
read, remoteAddr, err := socket.ReadFromUDP(data)
if err != nil {
fmt.Println("read data fail!", err)
continue
}
fmt.Println(read, remoteAddr)
fmt.Printf("%s\n\n", data)
// send data
senddata := []byte("hello client!")
_, err = socket.WriteToUDP(senddata, remoteAddr)
if err != nil {
return
fmt.Println("send data fail!", err)
}
}
}(conn)
}
wg.Wait()
}
func main() {
udp_server()
}
Is it OK for this test code?
答案1
得分: 31
net.Conn
的文档中提到:
> 多个goroutine可以同时调用Conn上的方法。
英文:
The documentation for net.Conn
says:
> Multiple goroutines may invoke methods on a Conn simultaneously.
答案2
得分: 3
多个 goroutine 可以同时在 Conn 上调用方法。
我对上面的文档的理解是,如果你从多个 goroutine 中调用 Read
和 Write
来操作一个 net.Conn
,不会发生灾难性的情况,并且对于从多个 goroutine 中的 net.Conn
调用 Write
,字节将会被串行化,这样两个不同的 Write
调用的字节在写入网络时不会交错。
你提供的代码的问题在于,Write
并不能保证一次性将整个字节切片写入。你忽略了已写入的字节数。
_, err = socket.WriteToUDP(senddata, remoteAddr)
所以为了确保你写入了所有的数据,你需要循环调用 Write
直到所有的 senddata
都被发送。但是 net.Conn
只能确保来自单个 Write
调用的数据不会交错。考虑到你可能会使用多次写入的方式发送单个数据块,不能保证这个单个数据块会完整地到达目的地。
所以例如,3 个 "hello client!" 消息可能以以下形式到达:
"hellohellohello client! client! client!"
因此,如果你想要在多个 goroutine 中可靠地向 net.Conn
写入消息,你需要同步这些 goroutine,以确保单个消息被完整地写入。
如果我想要做到这一点,作为第一次尝试,我会有一个单独的 goroutine 从一个或多个消息通道读取,并写入一个 net.Conn
,然后多个 goroutine 可以向这些消息通道写入。
英文:
> Multiple goroutines may invoke methods on a Conn simultaneously.
My interpretation of the doc above, is that nothing catastrophic will happen if you invoke Read
and Write
on a net.Conn
from multiple go routines, and that calls to Write
on a net.Conn
from multiple go routines will be serialised so that the bytes from 2 separate calls to Write
will not be interleaved as they are written to the network.
The problem with the code you have presented is that there is no guarantee that Write
will write the whole byte slice provided to it in one go. You are ignoring the indication of how many bytes have been written.
_, err = socket.WriteToUDP(senddata, remoteAddr)
So to make sure you write everything you would need to loop and call Write
till all the senddata
is sent. But net.Conn
only ensures that data from a single call to Write is not interleaved. Given that you could be sending a single block of data with multiple calls to write there is no guarantee that the single block of data would reach its destination intact.
So for example 3 "hello client!" messages could arrive in the following form.
"hellohellohello client! client! client!"
So if you want reliable message writing on a net.Conn
from multiple go routines you will need to synchronise those routines to ensure that single messages are written intact.
If I wanted to do this, as a first attempt I would have a single go routine reading from one or many message channels and writing to a net.Conn
and then multiple go routines can write to those message channels.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论