英文:
Go - Read data from TCP connection from multiple readers
问题
我正在使用Go编程语言处理云服务器的网络事务。我遇到了一个问题,即如何在不同的Goroutines中同时从相同的TCP连接读取数据。
以下是一个简单的示例:
package main
import (
"fmt"
"net"
)
func main() {
addr, _ := net.ResolveTCPAddr("tcp", ":8888")
listener, _ := net.ListenTCP("tcp", addr)
for {
conn, err := listener.AcceptTCP()
if err != nil {
fmt.Println(err)
return
}
go Handle(conn) // 输出总是来自这里
go Handle(conn)
}
}
func Handle(conn *net.TCPConn) {
data := make([]byte, 1024)
fmt.Println("Ok")
for {
len_data, err := conn.Read(data)
fmt.Println(err)
fmt.Println(len_data)
}
}
在这个示例中,控制台输出总是来自第一个Goroutine go Handle(conn)
...如何使两个Goroutines同时进行读取操作?
谢谢。
英文:
I'm working on Cloud Server's networking thing using Go programming language.
And I faced a problem with <b>reading same TCPconn at the same time from different Goroutines</b>.
Here is a simple example
package main
import (
"fmt"
"net"
)
func main() {
addr, _ := net.ResolveTCPAddr("tcp", ":8888")
listener, _ := net.ListenTCP("tcp", addr)
for {
conn, err := listener.AcceptTCP()
if err != nil {
fmt.Println(err)
return
}
go Handle(conn) // output always coming from here
go Handle(conn)
}
}
func Handle(conn *net.TCPConn) {
data := make([]byte, 1024)
fmt.Println("Ok")
for {
len_data, err := conn.Read(data)
fmt.Println(err)
fmt.Println(len_data)
}
}
In this example console output always coming from 1st goroutine <code>go Handle(conn)</code> ...
<p>How to make Read functionality from 2 Goroutines at the same time ?</p>
Thanks
答案1
得分: 2
一种方法是使用io.MultiWriter
和io.Pipe
:
func main() {
var wg sync.WaitGroup
r := strings.NewReader(hello)
pr1, pw1 := io.Pipe()
pr2, pw2 := io.Pipe()
pr3, pw3 := io.Pipe()
mw := io.MultiWriter(pw1, pw2, pw3)
wg.Add(4)
go process(&wg, 0, pr1)
go process(&wg, 1, pr2)
go process(&wg, 2, pr3)
go func() {
io.Copy(mw, r)
pw1.Close()
pw2.Close()
pw3.Close()
wg.Done()
}()
wg.Wait()
}
英文:
One way to do it is using io.MultiWriter
and io.Pipe
:
func main() {
var wg sync.WaitGroup
r := strings.NewReader(hello)
pr1, pw1 := io.Pipe()
pr2, pw2 := io.Pipe()
pr3, pw3 := io.Pipe()
mw := io.MultiWriter(pw1, pw2, pw3)
wg.Add(4)
go process(&wg, 0, pr1)
go process(&wg, 1, pr2)
go process(&wg, 2, pr3)
go func() {
io.Copy(mw, r)
pw1.Close()
pw2.Close()
pw3.Close()
wg.Done()
}()
wg.Wait()
}
答案2
得分: 0
开始一个单独的Go协程来执行conn.Read(data)
并将结果放入一个通道中。
然后(并发地,不等待第一个Go协程完成)开始多个Go协程从这个通道中读取。
由于conn
不是线程安全的(它只能在单个Go协程中运行,可能是因为MAXGOPROCS == 1
),你不希望直接从多个Go协程并发地读取conn
。
英文:
Start a single go routine to perform conn.Read(data) and put the result into a channel.
Then (concurrently, without waiting for the first go routine to finish) start multiple go routines to read from this channel.
You don't want to directly read from the conn concurrently from multiple go routine since it is not thread-safe (the fact that it runs, and only run only on a single go routine probably because your MAXGOPROCS == 1).
答案3
得分: -1
好的,首先,你做错了,朋友。
你应该创建工作线程(预先创建),创建通道,并将该通道与传入的连接进行聚合。然后,你应该在工作线程内部处理这个连接。这样,你将得到X个并发的工作线程,用于处理你的连接。
我已经为你写了一个很好的示例,展示了如何优雅地处理工作线程,但是没有时间写下如何优雅地处理传入的连接。尽管如此,你会明白我的意思。
希望对你有所帮助。
http://play.golang.org/p/YkQVmBEWly
英文:
Ok so first of all. You're doing it wrong friend.
What you should do is create workers (pre-create), create channel and aggregate that channel with incoming connections. Than you should take that same connection inside of worker and handle it. On this way you'll get X concurrent workers that runs against your connections.
I went ahead and wrote you down one nice example of how to gracefully handle workers but did not had time to write down how to gracefully handle incoming connections. Never the less, you'll see what i mean.
http://play.golang.org/p/YkQVmBEWly
Hope this helps,
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论