lxzan / gws

simple, fast, reliable websocket server & client, supports running over tcp/kcp/unix domain socket. keywords: ws, proxy, chat, go, golang...
https://pkg.go.dev/github.com/lxzan/gws
Apache License 2.0
1.41k stars 91 forks source link

Add `Write` related shortcut methods #1

Closed fzdwx closed 1 year ago

fzdwx commented 1 year ago

Add Method:

lxzan commented 1 year ago

Add Method:

  • WriteText
  • WriteBinary

WriteText可以有,你用StringReader改一改再提PR😄

fzdwx commented 1 year ago

直接用 copy 可以吗?我看了 strings.ReaderRead 用是这个。

func (c *Conn) WriteText(payload string) {
    bytes := make([]byte, 0, len(payload))
    copy(bytes, payload[0:])
    c.WriteMessage(OpcodeText, bytes)
}

为什么 WriteBinary 这个不用提供呢?

lxzan commented 1 year ago

直接用 copy 可以吗?我看了 strings.ReaderRead 用是这个。

func (c *Conn) WriteText(payload string) {
  bytes := make([]byte, 0, len(payload))
  copy(bytes, payload[0:])
  c.WriteMessage(OpcodeText, bytes)
}

为什么 WriteBinary 这个不用提供呢?

你好勤快啊,一大早就就来写代码了👍🏻 晚点合你的PR,一种opcode提供一个方法很合理.

lxzan commented 1 year ago

直接用 copy 可以吗?我看了 strings.ReaderRead 用是这个。

func (c *Conn) WriteText(payload string) {
    bytes := make([]byte, 0, len(payload))
    copy(bytes, payload[0:])
    c.WriteMessage(OpcodeText, bytes)
}

为什么 WriteBinary 这个不用提供呢?

你好勤快啊,一大早就就来写代码了👍🏻 晚点合你的PR,一种opcode提供一个方法很合理.

直接copy不行,多了一次alloc和copy

fzdwx commented 1 year ago

你说的 StringReaderstrings.Reader 吗?

lxzan commented 1 year ago

你说的 StringReaderstrings.Reader 吗?

不是. 我指的是io.Reader接口的一个实现,读一点内容然后游标偏移

fzdwx commented 1 year ago

我搜到了这个 https://segmentfault.com/a/119000003767958 ;它里面这的这种方式:

func convert(s string) []byte {
    sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
    bh := reflect.SliceHeader{
        Data: sh.Data,
        Len:  sh.Len,
        Cap:  sh.Len,
    }
    return *(*[]byte)(unsafe.Pointer(&bh))
}
lxzan commented 1 year ago

我搜到了这个 https://segmentfault.com/a/119000003767958 ;它里面这的这种方式:

func convert(s string) []byte {
  sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
  bh := reflect.SliceHeader{
      Data: sh.Data,
      Len:  sh.Len,
      Cap:  sh.Len,
  }
  return *(*[]byte)(unsafe.Pointer(&bh))
}

这个还不错, 性能和StringReader是一个级别的, safe实现更优雅点

fzdwx commented 1 year ago

老哥,我还没提交呢。。。

lxzan commented 1 year ago

你说的 StringReaderstrings.Reader 吗?

不好意思说错了, 是strings.Reader, 果然标准库已经实现了

fzdwx commented 1 year ago

但是 strings.Reader 用的就是 copy

fzdwx commented 1 year ago

image

这个是用 strings.NewReader,最快的还是 unsafe 的。

func Std(s string) []byte {
    reader := strings.NewReader(s)
    bytes := make([]byte, len(s))
    _, _ = reader.Read(bytes)
    return bytes
}
lxzan commented 1 year ago

但是 strings.Reader 用的就是 copy

往net.Conn写数据的时候才会copy, 那个开销是不可避免的

lxzan commented 1 year ago

image

这个是用 strings.NewReader,最快的还是 unsafe 的。

func Std(s string) []byte {
  reader := strings.NewReader(s)
  bytes := make([]byte, len(s))
  _, _ = reader.Read(bytes)
  return bytes
}
image

StringToBytes 是你那个unsafe实现

fzdwx commented 1 year ago

哈哈,咋还成差 300ns了。 Buffer 的实现和 strings.Reader的区别?

lxzan commented 1 year ago
image

代码已经提交到dev了, 你可以研究下

lxzan commented 1 year ago

大概是因为string不可变, 读string效率比[]byte高

lxzan commented 1 year ago

我搜到了这个 https://segmentfault.com/a/119000003767958 ;它里面这的这种方式:

func convert(s string) []byte {
    sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
    bh := reflect.SliceHeader{
        Data: sh.Data,
        Len:  sh.Len,
        Cap:  sh.Len,
    }
    return *(*[]byte)(unsafe.Pointer(&bh))
}

这个还不错, 性能和StringReader是一个级别的, safe实现更优雅点

image

前面的benchmark写的有点问题, buffer没有reset