(4.23)百度Golang一面凉经

(4.23)百度Golang一面凉经,第1张

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

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

写代码实现两个协程交替打印"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()
}

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
}

如果优雅关闭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
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/994586.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存