腾讯一面凉经-光子工作室

  • 自我介绍
  • 平常玩游戏吗?玩什么游戏
  • 对腾讯的印象
  • 对加班的看法
makenew的区别
    • new()方法传入一个值类型返回一个传入类型的指针,还会初始化内存空间
    • make()方法主要用来初始化channelmapslice,返回初始化类型的引用类型
func main() {
    // 返回*int
    a := new(int)
    // 赋值需要解引用
    *a = 2
    // 输出地址
    fmt.Pintln(a)
    // 输出值
    fmt.Println(*a)
    // 涉及到指针类型的时候初始化内存空间需要注意
    b := new(B)
    b.name = "test1"
    // 输出&{test1}
    fmt.Println(b)
    
    var c *B
    // panic
    c.name = "test2"
    fmt.Println(c)
    
    var c B
    c.name = "test2"
    // 输出{test2}
    fmt.Println(c)
}

type B struct {
    name string
}
channel相关
  • 向一个nil channel发送信息会发生什么
    • 永久阻塞导致死锁,会发生fatal error: all goroutines are asleep - deadlock!
  • 从一个nil channel接收消息会发生什么
    • 永久阻塞导致死锁,会发生fatal error: all goroutines are asleep - deadlock!
  • 以上两种情况的fatal error都是在所有协程进入阻塞或睡眠状态才会发生的报错
  • 向一个已经关闭的channel发送信息会发生什么
    • 会直接发生panic:panic: send on closed channel
  • 从一个已经关闭的channel接收消息会发生什么
    • 可以正常接收值,<-channel中可以返回两个值,第一个为接收到的值,第二个代表是否正常接受数据,如果channel已经关闭,第一个为传输数据类型的零值,第二个为false
  • channel是同步的还是异步的
    • 有缓存的channel是异步的,没有缓存的channel为同步的,在没有缓存的channel中传输数据时需要注意发送数据时会发生阻塞,如果没有协程进行读取数据就会发生fatal dead lock
// sendNilChannel 向一个nil channel发送数据
func sendNilChannel() {
    var ch1 chan int

    go func() {
        time.Sleep(2 * time.Second)
        fmt.Println("test")
    }()
    var a int
    // 永远阻塞,当子协程执行完成报错
    // fatal error: all goroutines are asleep - deadlock!
    a = <-ch1
    fmt.Println(a)
}

// resvNilChannel 从一个nil channel中读取数据
func resvNilChannel() {
    var ch1 chan int

    go func() {
        time.Sleep(2 * time.Second)
        fmt.Println("test")
    }()
    // 永远阻塞,当子协程执行完成报错
    // fatal error: all goroutines are asleep - deadlock!
    ch1 <- 2
}

// sendClosedChannel 向一个已经关闭的channel发送数据
func sendClosedChannel() {
    ch1 := make(chan int)
    close(ch1)
    // 发生panic panic: send on closed channel
    ch1<-1
}

// rersvClosedChannel 从一个已经关闭的channel接收数据
func resvClosedChannel() {
    ch1 := make(chan int)
    go func() {
        v, ok := <-ch1
        // 2, true
        fmt.Println(v, ok)
        close(ch1)
        // 0, false
        v, ok = <-ch1
        fmt.Println(v, ok)
    }()

    ch1<-2
    time.Sleep(2 * time.Second)
}

// syncChannel 同步channel
func syncChannel() {
    // 不设置缓冲区大小默认为0
    ch1 := make(chan int)
    go func() {
        fmt.Println(<-ch1)
    }()
    ch1 <- 1
    // 为了子协程能够正常接收数据,睡眠一秒
    time.Sleep(1 * time.Second)
}

// asyncChannel 异步channel
func asyncChannel() {
    // 创建一个缓冲区大小为2的channel
    ch1 := make(chan int, 2)
    // 因为存在缓冲区,所以在缓冲区没满时不会发生阻塞,会继续往下执行
    ch1 <- 1
    ch1 <- 2
    // 如果channel缓冲区已满就会发生阻塞等待缓冲区有剩余空间
    // ch1 <- 3
    // 打印输出1/n2/n
    fmt.Println(<-ch1)
    fmt.Println(<-ch1)
}
waitGroup传值会发生什么
// 正常执行
func n(wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Println("TEST2")
}

// 这时候的wg.Done()没有任何作用,协程执行完成后发生死锁报错,fatal error: all goroutines are asleep - deadlock!
// 在goland中会提示'p' passes a lock by the value: type 'sync.WaitGroup' contains 'interface{}' which is 'sync.Locker' 
// 就是这个原因导致waitGroup失效
func p(wg sync.WaitGroup) {
    defer wg.Done()
    fmt.Println("TEST1")
}
sync包里面的锁
  • sync包里都有哪些锁
    • sync.Mutex:互斥锁,同一时间只有一个协程能够使用
// A Mutex is a mutual exclusion lock.
// The zero value for a Mutex is an unlocked mutex.
//
// A Mutex must not be copied after first use.
type Mutex struct {
    state int32
    sema  uint32
}
    • sync.RWMutex
// A RWMutex is a reader/writer mutual exclusion lock.
// The lock can be held by an arbitrary number of readers or a single writer.
// The zero value for a RWMutex is an unlocked mutex.
// RWMutex是一个读写锁
// 这个锁可以被任意个读者或一个写着所使用
// 当值为0的时候RWMutex为没有被加锁

// A RWMutex must not be copied after first use.
// 一个读写锁在第一次被使用后一定不能被复制
//
// If a goroutine holds a RWMutex for reading and another goroutine might
// call Lock, no goroutine should expect to be able to acquire a read lock
// until the initial read lock is released. In particular, this prohibits
// recursive read locking. This is to ensure that the lock eventually becomes
// available; a blocked Lock call excludes new readers from acquiring the
// lock.
// 如果一个 goroutine 持有一个 RWMutex 用于读取并且另一个 goroutine 可能调用 Lock,Lock在这里为获取读写锁,
// 则没有 goroutine 应该期望能够获取读取锁直到最初的读锁被释放
// 特别是,这禁止递归读锁定。 这是为了确保锁最终可用; 
// 阻塞的 Lock 调用会阻止新读者获取锁,也就是说在一个协程申请读写锁的时候发生了阻塞,则后面所有协程的读锁都会被拒绝,再简单点就是说读写锁优先
type RWMutex struct {
    w           Mutex  // held if there are pending writers
    writerSem   uint32 // semaphore for writers to wait for completing readers
    readerSem   uint32 // semaphore for readers to wait for completing writers
    readerCount int32  // number of pending readers
    readerWait  int32  // number of departing readers
}
  • 加了写锁之后能加读锁吗,加了读锁后能加写锁吗
    • 加了写锁之后不能加读锁,加写锁会阻塞并拒绝所有请求的读锁
    • 读锁可以加任意个
context的作用
面向对象的三大特性
  • 封装
    • 封装是面向对象方法的重要原则,就是把对象的属性和操作(或服务)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节
    • 将类的某些信息隐藏在类的内部,不允许外部程序进行直接的访问调用
    • 通过该类提供的方法实现对隐藏信息的操作和访问
    • 隐藏对象的信息
    • 留出访问的对外接口
  • 继承
    • 继承就是子类继承父类的特征和行为,使得子类对象具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。在父类中拥有私有属性(private修饰),则子类是不能被继承的
    • 子类可以拥有父类的属性和方法
    • 子类可以拥有自己的属性和方法
    • 子类可以重写父类的方法
    • 可以提高代码复用性
    • 可以轻松的定义子类
    • 使设计应用程序变得简单
  • 多态
    • 多态是同一个行为具有不同表现形式或形态的能力
    • 消除类型之间的耦合关系,实现低耦合
    • 灵活性、可扩充性、可替换性
    • 体现形式:继承、父类引用指向子类、重写

select的作用
  • 语法跟switch相似,但case中监听的是发送或接收channel的语句,如果调用select时没有接收到case中的接收或发送channel的信号时,则会发生阻塞,当在seletct中使用default语句时,则会执行default后的语句
  • 当在同一时刻多个channel有响应时,go会使用一个伪随机算法进行定位到其中一个case进行执行
func main() {
    ch1 := make(chan int)
    go testSelect(ch1)
    // 主进程睡眠一秒
    time.Sleep(1 *  time.Millisecond)
    // 发送消息
    ch1<-2
    // 打印消息
    fmt.Println(<-ch1)
    // 睡眠3秒等待触发time out
    time.Sleep(3 * time.Second)
}

// 运行结果
// 1
// timeout
func testSelect(ch1 chan int) {
    // 死循环监听
    for {
        select {
        case <-ch1:
            ch1<- 1
        case <-time.After(2 *time.Second):
            fmt.Println("time out")
        }
    }
}
map中key为string类型,有序输出输出所有map中的所有元素
func main()  {
    mp := make(map[string]string)
    mp["c"] = "3"
    mp["b"] = "2"
    mp["a"] = "1"
    printSortMap(mp)
}

// 输出 1\n2\n3\n
func printSortMap(mp map[string]string) {
    var tmp []string
    for k := range mp {
        tmp = append(tmp, k)
    }
    quickSort(tmp, 0, len(tmp) - 1)
    for i := range tmp {
        fmt.Println(mp[tmp[i]])
    }
}

func quickSort(arr []string, l, r int) {
    if l >= r {
        return
    }
    j := partition(arr, l, r)
    quickSort(arr, l, j - 1)
    quickSort(arr, j + 1, r)
}

func partition(arr []string, l, r int) int {
    cur := arr[l]
    for l < r {
        for l < r && cur <= arr[r] {
            r--
        }
        arr[l], arr[r] = arr[r], arr[l]
        for l < r && cur > arr[l] {
            l++
        }
        arr[l], arr[r] = arr[r], arr[l]

    }
    return l
}
defer调用顺序
闭包
GMP
线程和协程的区别
异步IO和非阻塞IO的区别

非阻塞IO

异步IO

需要一直轮询,轮询过程中产生多次系统调用

不需要轮询

在数据准备好后的一次系统调用中再将数据从内核态复制到用户态中

数据未准备好直接返回,数据准备好后将数据从内核态中复制到用户态中,然后发送一个信号给进程表示已经完成了系统调用

死锁
  • 死锁发生的四个必要条件
    • 互斥性:在同一时刻一个资源只能被一个进程所使用
    • 不可剥夺性:一个资源在被一个进程使用完前不能被强制剥夺
    • 环形等待:所有进程形成一条首尾相连的环形资源等待链
    • 请求和保持:一个进程因为请求某一资源被阻塞时保持现在拥有的资源不放
gRPC优势
引用类型和值类型对象方法的区别

引用类型

值类型

引用类型方法可以改变对象中的属性

值类型方法可以不可以改变对象中的属性



引用类型和值类型对象实现接口的区别

如果实现接口的方法是引用类型,则不能返回一个结构体的实例返回给接口

type iInterface interface {
    SetName(name string)
}

type A struct {
    Name string
}

func newA() iInterface {
    return &A{
        Name: "test",
    }
}

func newA() iInterface {
    // wrong
    return A{
        Name: "test",
    }
}

func (a *A)SetName(name string) {
    a.Name = name
}
引用对象一定比值对象好吗
  • 不知道
c++ stl用过吗
c++ struct用过吗
反转链表Ⅱ
import (
    "bufio"
    "fmt"
    "os"
    "strconv"
    "strings"
)

type Node struct {
    next *Node
    val  int
}

func main() {
    var n int
    fmt.Scan(&n)
    reader := bufio.NewReader(os.Stdin)
    data, _, _ := reader.ReadLine()
    str := string(data)
    tmp := strings.Split(str, " ")
    head := &Node{}
    node := head
    head.next = node
    for i := range tmp{
        j, _:= strconv.Atoi(tmp[i])
        node.next = &Node{
            val: j,
        }
        node = node.next
    }
    var l, r int
    fmt.Scanf("%d %d", &l, &r)
    
    
    // 找到的是左边结点
    left := head
    var i int
    for ; i < l - 1; i++ {
        left = left.next
    }
    
    // 找右边的结点的上一个结点
    right := left
    for ;i < r ; i++ {
        right = right.next
    }
    
    // 记录左边开始结点和右边结尾结点
    newNext := left.next
    newRight := right.next
    
    // 断开结点
    left.next = nil
    right.next = nil
    
    // 反转链表
    pre := &Node{}
    cur := newNext
    for cur != nil {
        q := cur.next
        cur.next = pre
        pre = cur
        cur = q
    }
    
    newNext.next = newRight
    left.next = pre
    
    node = head.next
    for node != nil {
        fmt.Printf("%d ", node.val)
        node = node.next
    }
}
#腾讯实习##腾讯##面经#
全部评论
😅今年真难
点赞 回复 分享
发布于 2022-04-17 12:39
我也是光子一面凉,我面完自我感觉还挺好,结果还是挂了😅
点赞 回复 分享
发布于 2022-04-11 14:12
什么岗位呀
点赞 回复 分享
发布于 2022-04-02 12:50
怎么投的啊,投不了呢
点赞 回复 分享
发布于 2022-04-02 11:49
是怎么知道凉了啊,是官网状态变了吗
点赞 回复 分享
发布于 2022-04-02 11:48

相关推荐

02-15 21:02
已编辑
门头沟学院 Unity3D客户端
处女线上面&nbsp;kpi凉经&nbsp;一个鼠鼠狠狠地碎掉了😭😭面试官很高冷&nbsp;全程40多分钟拷打&nbsp;只有自己开着视频😂😂😂开篇面试官自我介绍&nbsp;&nbsp;然后自己的自我介绍问题∶1.聊聊怎么想到要学unity&nbsp;为什么准备想干这一行的有没有别的公司offer&nbsp;有没有实习过2.问了怎么学的unity&nbsp;是不是跟着教程做&nbsp;现在是大几3.问了数据持久化&nbsp;简历里项目的数据持久化有没有时效性(答的有点懵)4.问了unity里面生命周期函数&nbsp;着重问了三个update的区别&nbsp;追问了fixedupdate&nbsp;还有一些物理模拟5.围绕简历项目问了如何优化update里面cpu的计算(答了协程&nbsp;还有一些常见api的避免使用)6.追问了协程&nbsp;问了协程底层是怎么实现的7.问了有没有学过用过建模软件3DMAX&nbsp;Blender还有那个叫什么maya&nbsp;(不会&nbsp;没学过&nbsp;感觉减分很严重😅)8.问了项目里面动画相关的使用&nbsp;问了不了解骨骼Avatar那个东西&nbsp;有没有自己做过动画相关的东西9.会不会做地形模拟&nbsp;会不会用插件(会&nbsp;但是不熟)(减分了估计😭😭😭)10.反问&nbsp;&nbsp;问了公司base地&nbsp;问了公司目前项目进度和未来方向11.凉&nbsp;已读不回总结&nbsp;&nbsp;c#八股一个没问&nbsp;都是围绕unity问&nbsp;小厂还是注重直接上手unity&nbsp;还有看你个人潜力和对公司项目匹配度&nbsp;简历里会的多的一个没问&nbsp;问的应该全是实际项目中需要实习生干的脏活的&nbsp;感觉自己答的挺好的&nbsp;八股也准备了只能说跟公司目前需要的能力完全不沾边&nbsp;还得继续努力&nbsp;😁
查看11道真题和解析
点赞 评论 收藏
分享
02-13 10:39
已编辑
蚌埠坦克学院 UE4
11月投的,2月9号面试emm,此时我已经小厂实习了一个月了emm上来三道算法题,前两道lc简单题,一道字符串次数最多字符,一道数组去重,鼠鼠做数组去重的时候看急了,反正有各种原因,但其实就是本质彩笔,导致做完这两个题用了40分钟,面试官也一直提醒,这两道还是我之前做过的emm人怎么能那么笨,第三道random7写random10,鼠鼠没见过,后来一问也是经典题然后就是自己介绍项目,就是udemy的那个联机射击游戏Demo,主要是讲了实现的延迟组件,其中包括客户端预测和服务器倒带,最后总共1h25结束捏,面完后秒挂鼠鼠挂了后还问了面试官,面试官人很好,说一是算法确实做的慢,二是ue引擎没有深入了解,ue自己的移动组件的同步没有去看,也没有思考过100个人的优化问题总结,鼠鼠还是太着急了,其实这是鼠鼠第三次面试,面试经验不多,也是头一回面大厂,有点疾苦,因为之前投的大部分简历就没消息,有消息的一个微派,一个鼠鼠现在在的小厂,微派也是一面挂了,然后就来了现在这个小厂,在这待了1个月了,想说一下这里待的真的挺舒服的emm,之前可能工资太低,但是鼠鼠刚来的这一个月居然刚好给实习生加薪了,也是有当地平均水平力,还蹭到了异地的年会,报销了全程,需求感觉也挺好的,鼠鼠做逻辑的简历的结果被分到了引擎岗emm,不过因为项目很老所以还好鼠鼠没有被分到做gameplay,鼠鼠毕竟实力和bg都不好,所以也不奢求太多力发点牢骚,看到好多大佬的多段大厂实习总会让自己焦虑,觉得我实习晚了,实习段数少了什么的,后来也想了许多安慰自己的话,但觉得最有力度的还是不要让未来的自己懊悔现在的自己还在懊悔过去,最重要的永远是当下,过去已经发生的已经不可能改变,懊悔不仅无意义更是会毁了现在的自己,能做的永远都是现在,哪怕只是上一秒的自己也已经定格在了过去,还有什么这样的人生才是自己的人生啦等等鸡汤,但结果来说还是以悲伤为主嘛,不过一想,人总是要抗压的,那个罗兰怎么说来着?世界上只有一种真正的英雄主义,那就是在认清生活真相之后依然热爱它,规划好现在开始的每一天要完成什么目标,多做少想比较好呢结果鼠鼠的未来也是一片灰暗嘛,因为之前跟导员说实习的事,导员不放(为什么说,一是鼠鼠是学生心理,二是学校有扫脸,之前就有实习被逮的emm),一开始想跳了,觉得鼠鼠怎么那么傻,自断生路,后来跟校领导申请,两周多了还没信息,说是非常重视决定开会,感觉难,鼠鼠下学期一周还有10节课,学校这种体系怎么会因为鼠鼠一个而改变呢,算了,懒得管了,暑期实习也不用想了,唉英雄主义好难鼠鼠现在能做到就是继续做一个新的项目,就是udemy的那个超大的gas项目,鼠鼠本来上一年11月就说要做,结果嘛,到了现在才规划做,鼠鼠前面也懒嘛,又懒又焦虑的emm,现在每天做两个视频内h,看能不能两个月做完emm,鼠鼠的打算就是秋招前两个日常两个udemy的项目外加深入图形学鼠鼠就是因为爱打游戏才来游客的,以前打王者火影吃鸡什么的网游,二游打了崩原铁绝潮粥终(人生完蛋啦,这里面除了bbb我都还在玩,不过很多都是送东西才上号了),bbb我也算陪它到第一部结束力,大学有了电脑后玩了单机,泰拉呀,怪猎世界呀,老头环,空洞骑士,帕鲁什么什么的,最喜欢玩泰拉(我是国服召唤师,300h原版和灾厄大部分全是打的召唤师,现在大版本更新了又可以玩了)和怪猎世界(我是国服太刀侠emm),但不得不说老头环是全方面的好,特别是世界观给的代入感,真的有种异世界的感觉emm,空洞骑士是为了玩丝之歌买的,结果空洞骑士112了,丝之歌和大表哥都还在吃灰emm,空洞骑士我1.30h跑完苦痛,我是天才嘛(叉腰)不过我只打了4门,5门望而生却了emm,有个好朋友这些游戏全都跟我联机通关的,真好其实鼠鼠分享欲很强但因为喜欢二次元有社恐属性(难绷了),鼠鼠也没在整个学生生涯中谈过一次恋爱,其实鼠鼠也尝试过,不过都失败了(鼠鼠也难呐)最最最后,希望不管如何,大家都能快乐的生活,唉,好假大空,海绵宝宝,快乐都去哪了呢,我的话大一大二追新番的时候真的很快乐,我大学最喜欢的就是GBC,nina的性格真的跟以前的我挺像的,不过我没有nina可爱emm,败犬,mygo&amp;母鸡卡(懒得喷),辉夜,狐摇,末日酒店,小城日常等等好多好多,反正看动画太开心了,希望所有人都去看好看的动画,希望大家都能过得开心,实现自己的目标,现在说新年快乐会有种包饺子的感觉嘛()
查看1道真题和解析
点赞 评论 收藏
分享
评论
8
45
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务