超过两个goroutine的Go通道

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

Go channeling for more than two goroutines

问题

我不喜欢Go语言的一点是,通道接收操作会从通道中删除数据。这样只允许两个goroutine之间进行通信,即使有几种情况下两个或多个goroutine应该能够相互通信。

我知道我可以创建一个通道数组,并为每个goroutine分配一个通道,但是将数据从一个goroutine移动到所有其他goroutine上所需的内存要比将数据的一份副本移动到所有goroutine上所需的内存多得多。

想象一种情况,我有一千个客户端连接到服务器,我只想让其中的一半收到消息,也就是说有五百个goroutine接收该消息。如果消息大小为512字节,那么在内存中需要移动250千字节的数据,即使只需移动一次相同的数据也是可能的,如果通道在接收时不删除数据的话。

所以我想知道是否有一种简单的方法来实现这个,或者我必须使用sync包中的互斥锁?如果我计算错误,请告诉我,通道是否不会复制数据,因为在这种情况下我可以管理通道数组。

英文:

One thing I do not like about Go is that channel receive also removes the data from the channel. This only allows two goroutines to communicate with each other even though there are several cases when two or more goroutines should be able to talk to each other.

I know I could make an array of channels and have channel per goroutine, but moving data from one goroutine to all of the other goroutines is much more data on ram than moving one copy of the data to all goroutines.

Think about a case when I have thousand clients connected to server and I want one to send message to only half of them that is five hundred goroutines receiving that message. If the message is 512 bytes this becomes 250 kilobytes of data in the ram moving, even though it's possible to move the same data only once if channels would not remove the data on receive.

So I am asking if there is some simple way to do this or do I have to use mutex from the sync package? Though please tell me if I am calculating wrong and channels do not copy the data, because in that case I can just manage array of channels.

答案1

得分: 2

阅读这篇文章:

http://rogpeppe.wordpress.com/2009/12/01/concurrent-idioms-1-broadcasting-values-in-go-with-linked-channels/

这是一篇关于在Go语言中跨协程进行通道广播的不同方法的分析,其中有一种方法特别有趣:

type Broadcaster struct {
	Listenc	chan chan (chan broadcast);
	Sendc	chan<- interface{};
}

作者将这种方法称为“链接通道”(类似于链接列表)。

> 告诉我如果我计算错误并且通道不会复制数据,因为在这种情况下我可以只管理通道数组。

你没有错。正如@Jsor建议的那样,如果你担心复制开销并且使用情况允许,你可以只传递指针。

英文:

Read this article:

http://rogpeppe.wordpress.com/2009/12/01/concurrent-idioms-1-broadcasting-values-in-go-with-linked-channels/

It's an analysis on the different ways to channel-broadcast across goroutines, one of them being particularly interesting:

type Broadcaster struct {
	Listenc	chan chan (chan broadcast);
	Sendc	chan<- interface{};
}

This approach is called a "linked channel" (analagously to a linked list) by the author.

> tell me if I am calculating wrong and channels do not copy the data, because in that case I can just manage array of channels.

You're not wrong. As @Jsor suggested, though - you can just pass pointers around if you're afraid of copy-overhead and the use case allows it.

答案2

得分: 1

我通常会这样做:

type Message struct {
    text string
    address string
    ...
}

type Server {
    dropbox chan Message
    clients []*Conn
    ...
}

type Conn {
    inbox chan *Message
    ...
}

每个客户端都由一个读写协程提供服务,将“Message”放入“dropbox”中。服务器从“dropbox”中取出消息,并根据“address”确定要将消息发送给哪些客户端。

在服务器中,“clients”甚至可以是一个映射。这真的取决于您希望如何路由消息:特定的客户端、组等。

您可以使用chan chan T做一些聪明的事情,但如果您想要进行智能路由而不是盲目广播,您确实需要一种将消息映射到客户端的方式。

在这种情况下,您不需要互斥锁。互斥锁在某些情况下是最好的选择,但在这种情况下,通道更容易使用。

英文:

I typically do something like this:

type Message struct {
    text string
    address string
    ...
}

type Server {
    dropbox chan Message
    clients []*Conn
    ...
}

type Conn {
    inbox chan *Message
    ...
}

Each client, served by a reading/writing go routine, drops "Message" into "dropbox". The Server pulls messages out of "dropbox" and determines which clients to send the message to based on "address".

In Server "clients" can even be a map. It really depends on how you want to route the message: Specific clients, groups, etc.

You can do some clever things with chan chan T, but if you want to do intelligent routing instead of blind broadcasting, you really need some way to map the message to the client.

In this case you don't need a Mutex. There are cases where Mutexes are best, but in this case a channels are much easier.

huangapple
  • 本文由 发表于 2013年8月2日 15:42:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/18011435.html
匿名

发表评论

匿名网友

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

确定