(4.23)百度Golang一面凉经

数千道面试题尽在GolangRoadmap一个年轻的GO开发者社区https://www.golangroadmap.com/,目前是邀请制注册,邀请码:Gopher-1035-0722

感觉百度Go岗位相对C++还是少很多,面试是群面,换了两次面试官才匹配到一个Golang的,然后就被反复摩擦,还是太菜了!
上来简单自我介绍一下,没有问项目,直接开始问Golang

  1. 写代码实现两个协程交替打印"1",“2”,这是个比较经典的问题了,务必掌握。

    package main
    
    import (
    	"fmt"
    	"sync"
    )
    
    func main() {
    	var ch1, ch2 = make(chan struct{}), make(chan struct{})
    	var wg sync.WaitGroup
    	wg.Add(2)
    	go func(s string) {
    		defer wg.Done()
    		for i := 1; i <= 10; i++ {
    			<-ch1
    			fmt.Println(s)
    			ch2 <- struct{}{}
    		}
    		<-ch1
    	}("1")
    	go func(s string) {
    		defer wg.Done()
    		for i := 1; i <= 10; i++ {
    			<-ch2
    			fmt.Println(s)
    			ch1 <- struct{}{}
    		}
    	}("2")
    	ch1 <- struct{}{}
    	wg.Wait()
    }
    
  2. defer与返回值的问题,这个问题主要考察对return语句的理解,"return xxx"包含三个步骤
    (1)返回值=xxx
    (2)调用defer函数
    (3)将返回值返回
    当返回值没有声明时,你可以把返回值当作一个Go语言自己声明的变量,如下代码

    package main
    
    import "fmt"
    
    func main() {
    	fmt.Println(f1())//打印0
    }
    func f1() int {
    	var a int
    	defer func() {
    		a++
    	}()
    	//返回值=a,此时a=0
    	//执行defer,a++,此时a=1
    	//返回 返回值,返回值=0
    	return a
    }
    

    当返回值提前声明时

    package main
    
    import "fmt"
    
    func main() {
    	fmt.Println(f1())//打印1
    }
    func f1() (a int) {
    	
    	defer func() {
    		a++
    	}()
    	//返回值a=a,此时a=0
    	//执行defer,a++,此时a=1
    	//返回a
    	return a//等价与return
    }
    

    再看一种情况

    package main
    
    import "fmt"
    
    func main() {
    	fmt.Println(f1())//打印6
    }
    func f1() (a int) {
    	defer func() {
    		a++
    	}()
    	//返回值a=5
    	//执行a++,此时a=6
    	//返回a
    	return 5
    }
    

    再看一种情况

    package main
    
    import "fmt"
    
    func main() {
    	fmt.Println(f1())//打印5
    }
    func f1() (y int) {
    	x:=5
    	defer func() {
    		x++
    	}()
    	//y=x,此时x=5,y=5
    	//执行x++,此时x=6,y=5
    	//返回y
    	return x
    }
    

    最后一种情况

    package main
    
    import "fmt"
    
    func main() {
    	fmt.Println(f1())//打印6
    }
    func f1() (x int) {
    	defer func(x int) {
    		x++
    	}(x)
    	//x=5
    	//x++
    	//返回x
    	return 5
    }
    
  3. 如果优雅关闭http服务器
    http-server运行过程中,若进程被关闭,那么正在处理的请求可能只被处理了一半就停止了,可能会产生数据的不一致。
    优雅关机是指:首先,停止接收新请求;然后,等待队列中的请求被处理完毕;最后,应用程序退出;
    Golang http.Server 结构体有一个终止服务的方法 Shutdown,使用 Shutdown 可以优雅的终止服务,其不会中断活跃连接。其工作过程为:首先关闭所有开启的监听器,然后关闭所有闲置连接,最后等待活跃的连接均闲置了才终止服务。若传入的 context 在服务完成终止前已超时,则 Shutdown 方法返回 context 的错误,否则返回任何由关闭服务监听器所引起的错误。当 Shutdown 方法被调用时,Serve、ListenAndServe 及 ListenAndServeTLS 方法会立刻返回 ErrServerClosed 错误。请确保 Shutdown 未返回时,勿退出程序。
    signal 包的 Notify 函数提供系统信号通知的能力
    func Notify(c chan<- os.Signal, sig …os.Signal)
    参数 c 是调用者的信号接收通道,Notify 可将进入的信号转到 c。sig 参数为需要转发的信号类型,若不指定,所有进入的信号都将会转到 c。信号不会阻塞式的发给 c:调用者需确保 c 有足够的缓冲空间,以应对指定信号的高频发送。对于用于通知仅一个信号值的通道,缓冲大小为 1 即可。有了signal.Notify,传入一个 chan 并指定中断参数,这样当系统中断时,即可接收到信号。参看如下代码,当使用 Ctrl+C 时,c 会接收到中断信号,程序会在打印“program interrupted”语句后退出。

    func main() {
        c := make(chan os.Signal)
        signal.Notify(c, os.Interrupt)
        <-c
        log.Fatal("program interrupted")
    }
    

    接下来我们使用如上 signal.Notify 结合 http.Server 的 Shutdown 方法实现服务优雅的终止。如下代码,Handler其会在2s后返回 hello。创建一个 http.Server 实例,指定端口与 Handler。声明一个 processed chan,其用来保证服务优雅的终止后再退出主 goroutine。新启一个 goroutine,其会监听 os.Interrupt 信号,一旦服务被中断即调用服务的 Shutdown 方法,确保活跃连接的正常返回(本代码使用的 Context 超时时间为 3s,大于服务 Handler 的处理时间,所以不会超时)。处理完成后,关闭 processed 通道,最后主 goroutine 退出。

    var addr = flag.String("server addr", ":8080", "server address")
    
    func main() {
        // handler
        handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            time.Sleep(2 * time.Second)
            fmt.Fprintln(w, "hello")
        })
    
        // server
        srv := http.Server{
            Addr:    *addr,
            Handler: handler,
        }
    
        // make sure idle connections returned
        processed := make(chan struct{})
        go func() {
            c := make(chan os.Signal, 1)
            signal.Notify(c, os.Interrupt)
            <-c
    
            ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
            defer cancel()
            if err := srv.Shutdown(ctx); nil != err {
                log.Fatalf("server shutdown failed, err: %v\n", err)
            }
            log.Println("server gracefully shutdown")
    
            close(processed)
        }()
    
        // serve
        err := srv.ListenAndServe()
        if http.ErrServerClosed != err {
            log.Fatalf("server not gracefully shutdown, err :%v\n", err)
        }
    
        // waiting for goroutine above processed
        <-processed
    }
    

    Golang面试题

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值