stevewang

第 1556 号会员 /

回复了 stevenldj 创建的主题: ValueOf() 中的 Pointer() 和 UnsafeAddr() 的区别是什么?

以下代码p1和p2就是相等的。

package main

import (
    "fmt"
    "reflect"
)

func main() {
    var n int
    v1 := reflect.ValueOf(&n)
    v2 := v1.Elem()
    p1 := v1.Pointer()
    fmt.Println(reflect.TypeOf(p1), p1)
    p2 := v2.UnsafeAddr()
    fmt.Println(reflect.TypeOf(p2), p2)
}

回复了 aaa 创建的主题: 如何根据动态字符串,匹配同名函数.或匹配结构体

使用reflect可以实现,但是效率比较低而且缺少了编译时检查。

package main

import(
    "fmt"
    "errors"
    "reflect"
)

type Handler struct {
}

func (this *Handler) CallWithName(name string, args ...interface{}) error {
    value := reflect.ValueOf(this)
    method := value.MethodByName(name)
    if method == (reflect.Value{}) {
        return errors.New("not found")
    }
    if len(args) == 0 {
        method.Call(nil)
    } else {
        params := make([]reflect.Value, len(args))
        for i, arg := range args {
            params[i] = reflect.ValueOf(arg)
        }
        method.Call(params)
    }
    return nil
}

func (this *Handler) Hello(name string) {
    fmt.Printf("Hello, %s!\n", name)
}

func (this *Handler) Hi() {
    fmt.Println("Hi!")
}

func main() {
    var handler Handler
    handler.CallWithName("Hello", "aaa")
    handler.CallWithName("Hi")
    handler.CallWithName("hi")
}

回复了 aaa 创建的主题: sync.Pool的意义何在? 取值的顺序都是打乱的?

sync.Pool就是一个线程安全的对象缓冲池,可以获取和回收对象,缓冲池的大小会自动管理,避免过多的对象占用过多的内存。通过对缓冲池中对象的重复使用,以达到减少GC压力提高性能的目的。
如果应用场景中需要分配大量对象短暂使用之后就抛弃,就比较适合使用sync.Pool
注意,缓冲池只用于内存对象,不能用于文件和网络连接等资源,而且获取到的对象有可能是没有初始化的。

回复了 Zhangyc310 创建的主题: http.ListenAndServe(*http_addr, handle),如何设置keep-alive的时间?

下载文件不受影响,因为WriteTimeout没有修改。
http是短连接,每次请求都会创建一个新的连接。服务器没有办法知道第二个页面和第一个页面是同一个进程发起的请求,所以必须使用新的连接。
不过从客户端的角度说,是可以用一个连接请求多个资源的,比如http2协议就支持这种复用连接方式。

回复了 Zhangyc310 创建的主题: http.ListenAndServe(*http_addr, handle),如何设置keep-alive的时间?

设置了ReadTimeout以后,如果指定时间没有接收到数据,服务器就会关闭客户端连接。

package main

import (
    "fmt"
    "net"
    "net/http"
    "io"
    "time"
)

func ListenAndServe(addr string, handler http.Handler, timeout time.Duration) error {
    server := &http.Server{
        Addr:        addr,
        Handler:     handler,
        ReadTimeout: timeout,
    }
    return server.ListenAndServe()
}

func main() {
    addr := "127.0.0.1:6061"
    http.HandleFunc("/", func(http.ResponseWriter, *http.Request) {})
    go ListenAndServe(addr, nil, time.Second*10)
    time.Sleep(time.Second)
    started := time.Now()
    remoteAddr, _ := net.ResolveTCPAddr("tcp4", addr)
    conn, err := net.DialTCP("tcp4", nil, remoteAddr)
    if err != nil {
        panic("failed to connect")
    }
    defer conn.Close()
    _, err = conn.Read(make([]byte, 128))
    if err != io.EOF {
        panic("should return EOF")
    }
    fmt.Printf("time escaped=%s, error=%s\n", time.Now().Sub(started), err)
}

回复了 CaiNiao007 创建的主题: 处理httpServer的request时,多次创建大量对象,第三方实现的缓存池影响回收

如果处理每次请求时创建的大量对象是临时性的,可以使用sync.Pool
sync.Pool目前的实现是每次GC时都会销毁临时对象。所以如果你处理的请求不是很频繁,就不需要用到sync.Pool
至于第三方库就不好说了,因为和具体实现有关。
你所担心的问题实际上也不一定是问题,要测试发现性能瓶颈或者很明显可以预估到性能瓶颈,才需要进行性能调优。

回复了 shuaixinga 创建的主题: 学习GOLANG很久,还是感觉struct和interface很乱,如何解决?

比如 zip.NewWriter(io.Writer) 明明需要一个bytes.Buffer(当然其实现了io.Writer);

谁说的zip.NewWriter需要bytes.Buffer?只要是io.Writer都可以。在有的应用场景下,完全可以把一个*os.File传给zip.NewWriter;如果是web服务,还可以把http.ResponseWriter作为参数。

这个其实就是interface的强大之处。

关于标准库的封装,以精炼为原则,只要提供足够的基础功能就可以了,不应该搞的太繁杂。当然如果有个功能很多情况都需要用到,就可以加入标准库,比如1.7里加入标准库的context。毕竟标准库要加新的东西不会引起兼容性问题,但是如果要删去功能,旧程序就不能编译了。

回复了 q464610036 创建的主题: 关于结构体复制问题

用unsafe可以做到,但是很不安全,强烈不推荐:

    type A struct {
        ID   int
        Name string
    }
    type B struct {
        ID   int
        Name string
    }
    var a = A{
        ID: 1,
        Name: "Instance of A",
    }
    var b B = *(*B)(unsafe.Pointer(&a))

如果挨个成员赋值嫌麻烦,可以封装成一个函数就方便了:

func BuildBFromA(a *A) B {
    return B{
        ID:   a.ID,
        Name: a.Name,
    }
}