写点什么

小红书冲上热搜,大家都听说了吗?

作者:王中阳Go
  • 2025-01-16
    湖南
  • 本文字数:3808 字

    阅读完需:约 12 分钟

小红书冲上热搜,大家都听说了吗?

由于一些特殊原因,小红书上突然涌现出一大批外国用户,他们自称是**“某 k 的难民”**,开始在小红书上分享内容。


不过,小红书目前还没有自带的翻译功能,不会中文的外国用户只能使用英文或使用第三方翻译软件与中国用户进行交流。同时,多种语言来袭,也给小红书平台带来了内容审核的压力


据经济观察网报道,一位接近小红书的人士表示,小红书内部团队从 1 月 13 日当天就开始加班了,正在针对外国用户做功能优化,他们希望努力承接这波流量。


不知道有没有在小红书上班的朋友,在评论区分享一下你的故事~


由于这个事情,我也特意整理了一些小红书的 golang 面经,感兴趣的朋友可以接着往下看:



以下是详细答案:

channel 关闭之前和关闭之后的读取情况如何?

答案:


当通道被关闭后,对其发送操作会引发 panic,因为通道已经关闭,任何进一步的写入都将失败。对于读取操作,如果通道关闭前有未读的数据,那么这些数据可以被正确读取。如果通道关闭前没有未读的数据,那么读取操作将立即返回通道元素的零值(对于非阻塞读取)或者返回 false(对于阻塞读取)。在通道关闭后,默认情况下读取操作会返回通道元素的零值和 true,除非在关闭前最后一个接收操作之后还有其他接收操作。

请阐述 Golang 中 map 的哈希桶迁移机制。

答案:


Go 语言中的 map 底层是一个哈希表,当 map 中的元素数量不断增加,装载因子超过阈值(通常是 6.5)或哈希冲突过多时会触发扩容。扩容时会创建一个新的更大的哈希表,新的哈希表的大小通常是旧哈希表的两倍。然后将旧哈希表中的每个元素重新计算哈希值,并根据新的哈希表大小将其放入新的桶中,这个过程就是哈希桶迁移。Go 语言使用渐进式扩容技术,不会一次性完成所有元素的迁移,而是将迁移过程分散到后续的插入和查找操作中。

sync.map 和普通 map

答案:


  • 并发安全性:普通 map 在没有外部同步的情况下,不是并发安全的,在多 goroutine 访问时,如果没有适当的锁或其他同步机制保护,可能会导致数据竞争和未定义行为。而 sync.Map 是并发安全的,它内部实现了必要的同步机制,允许多个 goroutine 同时读写而不会引发数据竞争问题。

  • 性能:普通 map 对于单线程或同步控制下的访问,性能通常优于 sync.Map,因为它避免了额外的同步开销。sync.Map 由于其内部的读写锁和复杂的逻辑,在并发访问下虽然保证了安全,但可能比直接操作普通 map 慢一些,不过在高并发且读多写少的场景下,它的性能损失相对较小。

  • 使用场景:普通 map 适用于单线程环境或在有明确同步控制的多 goroutine 环境中。sync.Map 适用于无须显式锁控制的多 goroutine 共享数据场景,比如作为缓存、计数器等,特别是在读远多于写的场景下表现更佳。

阐述对 context 的理解(使用及原理)

答案:


  • 使用:在 Go 语言中,context 主要用于在多个 goroutine 之间传递上下文信息,如请求的截止时间、取消信号、共享数据等。比如在一个 HTTP 服务器中,每个请求都可以有自己的 context,用于在处理请求的各个阶段传递和共享相关信息,当请求超时或被取消时,可以通过 context 及时通知各个处理函数停止工作。

  • 原理:context 的核心是一个接口类型,包含了获取截止时间、取消信号、获取键值对等方法。它通过树状结构来管理和传递上下文信息,根节点通常是由程序的主函数或框架初始化创建,子节点可以通过父节点衍生而来,当父节点的上下文发生变化,如被取消或超时,子节点会继承这些变化并及时做出响应。

对比 Golang 的协程与进程、线程,并说明 CPU 如何运行进程。

答案:


  • 协程与进程:进程是操作系统资源分配的基本单位,拥有独立的内存空间和系统资源,进程之间相互隔离。而协程是一种轻量级的用户态线程,由程序自身管理和调度,多个协程可以在同一个进程内共享内存和其他资源,协程的创建和销毁成本比进程低很多,切换开销也远小于进程切换。

  • 协程与线程:线程是操作系统调度的基本单位,线程之间共享进程的内存空间,但线程的创建和切换开销相对协程较大。协程的调度更加灵活,可以由程序根据自身的业务逻辑进行调度,而线程的调度由操作系统内核决定。

  • CPU 运行进程:CPU 通过时间片轮转的方式来运行进程,操作系统会为每个进程分配一定的时间片,当进程获得 CPU 时间片时,CPU 会从进程的指令指针所指向的位置开始执行指令,执行完一个时间片后,如果进程未结束,操作系统会保存进程的上下文信息,然后将 CPU 分配给其他进程,当再次轮到该进程时,再恢复其上下文信息继续执行。

Redis 的数据类型

答案:

基础数据类型

  • 字符串(String):是最基本的数据类型,可以存储任何形式的字符串,包括整数、浮点数等,常用于缓存、计数器、分布式锁等场景。

  • 列表(List):是一个字符串列表,按照插入顺序排序,可以在列表的两端进行插入和删除操作,常用于消息队列、任务队列等场景。

  • 哈希(Hash):是一个键值对集合,类似于 Java 中的 Map,常用于存储对象的属性、用户信息等。

  • 集合(Set):是一个无序的字符串集合,不允许重复元素,常用于存储标签、用户关系等。

  • 有序集合(Sorted Set):是一个有序的字符串集合,每个元素都有一个分数,可以根据分数进行排序,常用于排行榜、优先级队列等场景。

高级数据类型

  • 地理空间(Geospatial)

  • 功能:用于存储和操作地理空间位置信息。

  • 应用场景:适用于地图应用、位置服务、附近的人等功能的实现。

  • Hyperloglogs

  • 功能:用于统计基数数量,即不重复元素的数量,与 Set 类似,但只记录存入的元素数量,不记录存入元素的具体值。

  • 应用场景:常用于大数据场景下的去重计数,如统计网站的独立访客数量等,相比 Set 可以节省大量内存空间。

  • Bitmaps

  • 功能:实际上也是一种 key-value,Bitmaps 的 value 只能是 0 或 1,Bitmaps 的 key 代表偏移量是“数位”的位置,可以用于记录状态、统计信息等。

  • 应用场景:例如记录用户的登录状态、每周的打卡情况等,通过位运算可以高效地进行统计和查询。

Dockerfile 中 add 和 copy 的区别是什么?

答案:


  • 功能上:add 命令除了可以将本地文件或目录复制到镜像中,还可以自动解压一些压缩文件,如 tar、gz 等格式的文件。而 copy 命令只能单纯地将本地文件或目录复制到镜像中,不会进行解压操作。

  • 使用场景上:如果只是简单地复制文件或目录,建议使用 copy 命令,因为它的功能更单一,行为更明确。如果需要在复制的同时进行解压操作,或者需要从远程 URL 获取文件并解压到镜像中,则可以使用 add 命令。

  • 安全性上:由于 add 命令会自动解压文件,可能会存在安全风险,如意外解压恶意文件等。因此,在使用 add 命令时需要特别小心,确保复制的文件来源可靠。

请谈谈服务发现和服务注册、服务治理相关内容。

答案:


  • 服务发现:是指在分布式系统中,服务消费者能够自动发现服务提供者的地址和端口等信息的过程。通常采用的方式有基于 DNS 的服务发现、基于注册中心的服务发现等。例如,在微服务架构中,当一个服务需要调用另一个服务时,它可以通过服务发现机制获取到目标服务的实例列表,然后根据负载均衡策略选择一个实例进行调用。

  • 服务注册:是服务提供者将自身的服务信息注册到注册中心的过程,服务信息包括服务名称、地址、端口、协议等。服务提供者在启动时会向注册中心发送注册请求,注册中心会保存这些信息。当服务提供者的信息发生变化时,如地址或端口变更,也需要及时更新到注册中心。

  • 服务治理:是对分布式系统中的服务进行管理和协调的一系列活动,包括服务的监控、流量控制、熔断降级、配置管理等。通过服务治理,可以确保系统的稳定性、可靠性和性能。例如,当某个服务出现故障或性能下降时,可以通过熔断机制暂时切断对该服务的调用,避免故障扩散;当流量过大时,可以通过流量控制机制限制对某些服务的访问频率,保护系统的稳定性。

如何在 Linux 中查看 CPU 利用率以及查看指定进程的情况?

答案:


  • 查看 CPU 利用率:可以使用 top 命令,它会实时显示系统中各个进程的 CPU 使用率、内存使用率等信息,在 top 命令的输出中,第一行显示的是系统的总体 CPU 利用率,包括用户态、内核态、空闲等各个状态的占比。也可以使用 mpstat 命令,它可以更详细地查看每个 CPU 核心的利用率情况。

  • 查看指定进程的情况:可以使用 ps 命令,如 ps -ef 可以列出系统中所有的进程信息,包括进程的 PID、PPID、CPU 使用率、内存使用率等。还可以使用 top -p <PID>命令,其中<PID>是指定进程的 PID,这样可以只查看指定进程的详细信息,包括实时的 CPU 使用率、内存使用率、线程信息等。另外,也可以使用 pmap 命令查看指定进程的内存映射情况。

编写代码实现:使用两个协程交叉打印单数和双数。

答案:


package main
import ( "fmt" "sync")
func printOdd(wg *sync.WaitGroup, ch chan struct{}) { defer wg.Done() for i := 1; i <= 10; i += 2 { <-ch fmt.Println(i) ch <- struct{}{} }}
func printEven(wg *sync.WaitGroup, ch chan struct{}) { defer wg.Done() for i := 2; i <= 10; i += 2 { <-ch fmt.Println(i) ch <- struct{}{} }}
func main() { var wg sync.WaitGroup ch := make(chan struct{}, 1) ch <- struct{}{}
wg.Add(2) go printOdd(&wg, ch) go printEven(&wg, ch)
wg.Wait() close(ch)}
复制代码


通过创建一个容量为 1 的 channel 来控制两个协程的执行顺序,实现交叉打印单数和双数。

欢迎关注 ❤

我们搞了一个免费的面试真题共享群,互通有无,一起刷题进步。


没准能让你能刷到自己意向公司的最新面试题呢。


感兴趣的朋友们可以加我微信:wangzhongyang1993,备注:infoq 面试群。

用户头像

王中阳Go

关注

靠敲代码在北京买房的程序员 2022-10-09 加入

【微信】wangzhongyang1993【公众号】程序员升职加薪之旅【成就】InfoQ专家博主👍掘金签约作者👍B站&掘金&CSDN&思否等全平台账号:王中阳Go

评论 (1 条评论)

发布
用户头像
有在小红书上班的朋友吗?
刚刚 · 湖南
回复
没有更多了
小红书冲上热搜,大家都听说了吗?_Go_王中阳Go_InfoQ写作社区