• Golang Tips


    1)请注意,返回一个局部变量的地址完全没有问题,这点与C不同。该局部变量对应的数据 在函数返回后依然有效。

    func NewFile(fd int, name string) *File {
    	if fd < 0 {
    		return nil
    	}
    	f := File{fd, name, nil, 0}
    	return &f
    }

    2)
    make(T, args) 的目的不同于 new(T)。它只用于创建切片、映射和信道,并返回类型为 T(而非 *T)的一个已初始化 (而非置零)的值。
    make([]int, 10, 100)
    会分配一个具有100个 int 的数组空间,接着创建一个长度为10, 容量为100并指向该数组中前10个元素的切片结构。

    切片是对数组的封装。

    3)Map
    与切片一样,映射也是引用类型。 若将映射传入函数中,并更改了该映射的内容,则此修改对调用者同样可见。

    4)
    %T,它会打印某个值的类型

    5)常量
    type ByteSize float64
    
    const (
        // 通过赋予空白标识符来忽略第一个值
        _           = iota // ignore first value by assigning to blank identifier
        KB ByteSize = 1 << (10 * iota)
        MB
        GB
        TB
        PB
        EB
        ZB
        YB
    )

    6)channel

    信道有很多惯用法,我们从这里开始了解。在上一节中,我们在后台启动了排序操作。 信道使得启动的Go程等待排序完成。

    c := make(chan int)  // 分配一个信道
    // 在Go程中启动排序。当它完成后,在信道上发送信号。
    go func() {
    	list.Sort()
    	c <- 1  // 发送信号,什么值无所谓。
    }()
    doSomethingForAWhile()
    <-c   // 等待排序结束,丢弃发来的值。
    

    接收者在收到数据前会一直阻塞。若信道是不带缓冲的,那么在接收者收到值前, 发送者会一直阻塞;若信道是带缓冲的,则发送者仅在值被复制到缓冲区前阻塞; 若缓冲区已满,发送者会一直等待直到某个接收者取出一个值为止。

    带缓冲的信道可被用作信号量,例如限制吞吐量。在此例中,进入的请求会被传递给 handle,它从信道中接收值,处理请求后将值发回该信道中,以便让该 “信号量”准备迎接下一次请求。信道缓冲区的容量决定了同时调用 process 的数量上限,因此我们在初始化时首先要填充至它的容量上限。

    var sem = make(chan int, MaxOutstanding)
    
    func handle(r *Request) {
    	sem <- 1 // 等待活动队列清空。
    	process(r)  // 可能需要很长时间。
    	<-sem    // 完成;使下一个请求可以运行。
    }
    
    func Serve(queue chan *Request) {
    	for {
    		req := <-queue
    		go handle(req)  // 无需等待 handle 结束。
    	}
    }
    

    然而,它却有个设计问题:尽管只有 MaxOutstanding 个Go程能同时运行,但 Serve 还是为每个进入的请求都创建了新的Go程。其结果就是,若请求来得很快, 该程序就会无限地消耗资源。为了弥补这种不足,我们可以通过修改 Serve 来限制创建Go程,这是个明显的解决方案,但要当心我们修复后出现的Bug。

    func Serve(queue chan *Request) {
    	for req := range queue {
    		sem <- 1
    		go func() {
    			process(req) // 这儿有Bug,解释见下。
    			<-sem
    		}()
    	}
    }

    Bug出现在Go的 for 循环中,该循环变量在每次迭代时会被重用,因此 req 变量会在所有的Go程间共享,这不是我们想要的。我们需要确保 req 对于每个Go程来说都是唯一的。有一种方法能够做到,就是将 req 的值作为实参传入到该Go程的闭包中:

    func Serve(queue chan *Request) {
    	for req := range queue {
    		sem <- 1
    		go func(req *Request) {
    			process(req)
    			<-sem
    		}(req)
    	}
    }

    另一种管理资源的好方法就是启动固定数量的 handle Go程,一起从请求信道中读取数据。Go程的数量限制了同时调用 process 的数量。Serve 同样会接收一个通知退出的信道, 在启动所有Go程后,它将阻塞并暂停从信道中接收消息。

    func handle(queue chan *Request) {
    	for r := range queue {
    		process(r)
    	}
    }
    
    func Serve(clientRequests chan *Request, quit chan bool) {
    	// 启动处理程序
    	for i := 0; i < MaxOutstanding; i++ {
    		go handle(clientRequests)
    	}
    	<-quit  // 等待通知退出。
    }
  • 相关阅读:
    Python从入门到精通之First!
    如果你不懂计算机语言,那么就请你不要说你是学计算机的!!好丢人。。。
    shell脚本-编程前奏-小工具之grep(文本处理)
    实战之授权站点漏洞挖掘-git信息泄漏
    实战之授权站点漏洞挖掘-CVE-2015-2808
    实战之授权站点漏洞挖掘-HTTP.sys远程代码执行
    实战之授权站点漏洞挖掘-CVE-1999-0554
    实战之授权站点漏洞挖掘-CORS
    实战之授权站点漏洞挖掘-越权
    实战之授权站点漏洞挖掘-url重定向
  • 原文地址:https://www.cnblogs.com/gm-201705/p/8301690.html
Copyright © 2020-2023  润新知