Golang – 在扇入中进行排序

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

Golang - Sorting on fan in

问题

我正在随机生成一堆日志消息,生成后,我需要按时间戳对它们进行排序,然后将它们写入日志。我正在利用sort库的sort.Interface特性,以便根据时间戳进行排序。我正在使用一个并发设计的扇入模式,所以我的排序函数会聚合所有来自goroutine的日志消息,然后对它们进行排序。

以下是我的代码:

type CommonLogFormat struct {
    HostIP         string
    UserIdent      string
    User           string
    Timestamp      string
    Request        string
    HttpStatusCode int
    Size           int
}

type Logs struct {
    Messages []*CommonLogFormat
}

func sortByTimestamp(ch chan<- *CommonLogFormat) *Logs {
    logs := &Logs{Messages: make([]*CommonLogFormat, 0)}

    for i := range ch {
        logs.Messages = append(logs.Messages, i)
    }

    sort.Sort(logs)

    return logs
}

func (l Logs) Len() int {
    return len(l.Messages)
}

func (l Logs) Less(i, j int) bool {
    return l.Messages[i].Timestamp < l.Messages[j].Timestamp
}

func (l *Logs) Swap(i, j int) {
    l.Messages[i], l.Messages[j] = l.Messages[j], l.Messages[i]
}

然而,当我尝试从通道接收日志消息时,我遇到了以下错误:

invalid operation: <-i (receive from non-chan type *CommonLogFormat)

为什么我无法从通道接收值?

英文:

I am randomly generating a bunch of log messages, and after they have been generated, I need to sort them by timestamp before writing them to the logs. I'm utilising the sort.Interface aspect of the sort library so I can sort based on my timestamp. I'm using a fan-in concurrency design, so my sorting function aggregates all the log messages from the goroutines, then sorts them.

Here is my code:

type CommonLogFormat struct {
	HostIP         string
	UserIdent      string
	User           string
	Timestamp      string
	Request        string
	HttpStatusCode int
	Size           int
}

type Logs struct {
	Messages []*CommonLogFormat
}

func sortByTimestamp(ch chan &lt;- *CommonLogFormat) *Logs {
	logs := &amp;Logs{Messages: make([]*CommonLogFormat, 1)}

	for i := range ch {
		logs.Messages = append(logs.Messages, &lt;- i)
	}

	sort.Sort(logs)

	return logs
}

func (l Logs) Len() int {
	return len(l.Messages)
}

func (l Logs) Less(i,j int) bool {
	return l.Messages[i].Timestamp &lt; l.Messages[j].Timestamp
}

func (l *Logs) Swap(i,j int) {
	l.Messages[i], l.Messages[j] = l.Messages[j], l.Messages[i]
}

However, when I go to receive a log message from the channel, I get this error:

invalid operation: &lt;-i (receive from non-chan type *CommonLogFormat)

Why can't I receive a value from the channel?

答案1

得分: 2

我认为错误信息已经很明显了。看看这段代码:

for i := range ch {
    logs.Messages = append(logs.Messages, <-i)
}

ch 的类型是 chan<- *CommonLogFormat,也就是一个通道。for range 循环遍历通道,将通道中发送的值存储在循环变量 i 中。i 不是一个通道,而是通道中发送的值,所以它的类型是 *CommonLogFormat

所以没有必要,也不能从中接收,因为它已经是你想要接收的值了。只需简单地将 i 追加到 logs.Messages 中:

for i := range ch {
    logs.Messages = append(logs.Messages, i)
}

规范:For 语句 中详细说明了在 for range 的情况下循环变量的含义:

Range 表达式                          第一个值          第二个值

数组或切片  a  [n]E, *[n]E, or []E    索引    i  int    a[i]       E
字符串          s  string 类型            索引    i  int    参见下文  rune
映射             m  map[K]V                键      k  K      m[k]       V
通道         c  chan E, <-chan E       元素  e  E

最后一行适用于遍历通道的情况,第一个迭代值是元素。

> 对于通道,产生的迭代值是在通道上发送的连续值,直到通道被关闭为止。如果通道为 `nil`,则 range 表达式将永远阻塞。

  [1]: https://golang.org/ref/spec#For_statements
  [2]: https://golang.org/ref/spec#Close
英文:

I think the error message is pretty self-explanatory. Look at this:

for i := range ch {
    logs.Messages = append(logs.Messages, &lt;- i)
}

ch is of type chan &lt;- *CommonLogFormat. ch is a channel. The for range loop over the channel yields the values sent on the channel, which will be stored in the loop variable i. i is not a channel, but the values sent on the channel, so it will be of type *CommonLogFormat.

So no need, and you actually can't receive from it, it is already what you would want to receive from it. Simply append i:

for i := range ch {
    logs.Messages = append(logs.Messages, i)
}

The Spec: For statements details what the loop variables are in case of for range:

Range expression                          1st value          2nd value

array or slice  a  [n]E, *[n]E, or []E    index    i  int    a[i]       E
string          s  string type            index    i  int    see below  rune
map             m  map[K]V                key      k  K      m[k]       V
channel         c  chan E, &lt;-chan E       element  e  E

The last line applies in case of ranging over a channel, and the first iteration value is the element.

> For channels, the iteration values produced are the successive values sent on the channel until the channel is closed. If the channel is nil, the range expression blocks forever.

huangapple
  • 本文由 发表于 2016年12月5日 04:05:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/40963042.html
匿名

发表评论

匿名网友

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

确定