Erlang 面试题及详细答案(企业实战版)_第1页
Erlang 面试题及详细答案(企业实战版)_第2页
Erlang 面试题及详细答案(企业实战版)_第3页
Erlang 面试题及详细答案(企业实战版)_第4页
Erlang 面试题及详细答案(企业实战版)_第5页
已阅读5页,还剩5页未读, 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Erlang面试题及详细答案(企业实战版)一、基础语法与数据类型(初级)1、Erlang有哪些核心数据类型?各自特点是什么?参考答案:Erlang数据类型分为基本类型和复合类型,所有变量均为不可变,一旦赋值无法修改。1)基本类型:整数、浮点数:支持大整数运算,无溢出问题,金融、计数场景友好。原子(atom):全局唯一常量,编译期确定,常驻内存,匹配效率极高,常用于状态标记、消息标识。布尔值:本质是原子true/false,无单独布尔类型。字符串:本质是整数列表,双引号字符串等价于ASCII数字列表,效率较低,长文本优先用二进制。二进制(binary):紧凑二进制存储,读写效率高,网络、文件、协议解析核心类型。2)复合类型:列表(list):链式递归结构,尾部追加效率低,头部插入/读取效率高,支持模式匹配。元组(tuple):固定长度容器,随机访问快,常用于存储结构化数据、函数返回多值。映射(map):键值对结构,高版本Erlang支持,替代proplist做结构化存储,查询效率更高。函数(fun):一等公民,可作为参数传递、返回、存储,支持高阶编程。进程PID、引用、端口:系统资源类型,用于进程通信、资源标识。2、变量不可变的特性,对Erlang编程有什么影响?参考答案:Erlang变量是单次绑定,只能赋值一次,重新赋值会直接报错,这是语言核心特性之一。优势:彻底规避多线程并发下的变量竞争、脏数据问题,天然适配并发编程;代码可复现、可调试,函数入参固定则输出一定固定,无副作用;简化垃圾回收逻辑,无需处理变量修改后的内存变动。劣势与编码习惯:无法通过修改变量实现逻辑,需要用递归、新变量覆盖实现状态更新;习惯命令式编程的开发者需要适配递归思维,避免写出冗余代码。3、列表和元组的核心区别?业务场景如何选择?参考答案:核心区别:结构不同:列表是动态链式结构,长度可变;元组是固定长度连续内存结构,定义后长度不可变。性能不同:列表头部操作快、尾部操作极慢;元组随机访问、遍历效率远高于列表。匹配规则不同:列表支持头尾拆分匹配,元组支持固定位置模式匹配。场景选择:用列表:不确定长度、需要频繁头部增删、遍历迭代场景(遍历数据集合);用元组:固定结构数据、多返回值、结构体封装、键值固定的配置数据。二、函数与模式匹配(初级/中级)1、Erlang模式匹配的执行规则是什么?匹配优先级如何?参考答案:Erlang函数、case、receive均基于模式匹配执行,核心规则:从上到下依次匹配,匹配成功立即执行对应分支,不再向后匹配;常量、原子、固定结构匹配优先级高于变量匹配;变量可以匹配任意值,且绑定变量值,下划线_为匿名变量,匹配不绑定、不报错;支持嵌套匹配,列表、元组、映射均可逐层模式匹配。注意:编写函数时,通用匹配分支必须放在最后,否则会覆盖后续精准分支,导致逻辑失效。2、递归和尾递归的区别?Erlang为什么推荐尾递归?参考答案:普通递归:函数调用自身后,还需要执行后续计算,栈帧不会立即释放,递归深度过大会堆积栈内存,造成内存飙升、性能下降。尾递归:函数最后一步操作是调用自身,无后续计算,编译器会优化复用当前栈帧,不会产生栈堆积,内存占用恒定。Erlang无for/while循环,所有循环逻辑均依赖递归实现,业务中批量处理数据、遍历集合必须用尾递归,否则大数据量场景会出现内存溢出、卡顿问题。3、说说守卫表达式(guard)的作用和使用限制参考答案:守卫表达式是模式匹配后的条件判断,用于精准过滤匹配结果,语法为when条件。作用:解决单纯模式匹配无法实现的逻辑判断,比如数值大小判断、类型判断、空值过滤。限制:守卫表达式中不能调用自定义函数,仅允许Erlang内置BIF函数(如is_integer/1、length/1、+/-/比较运算等),目的是保证守卫判断无副作用、可编译期优化。三、进程与并发核心(中级高频)1、Erlang进程和操作系统线程的区别?为什么Erlang支持超高并发?参考答案:Erlang进程是虚拟机级别的轻量级进程,和系统线程完全不同:资源占用极低:单个Erlang进程栈内存仅几KB,创建、销毁成本极低;系统线程栈通常几MB,资源开销大。调度机制不同:Erlang由VM自主调度,用户态调度,无内核态切换开销;系统线程依赖操作系统内核调度,切换成本高。隔离性更强:Erlang进程内存完全独立,一个进程崩溃不会影响其他进程;线程共享进程内存,单线程异常易引发整体崩溃。超高并发原因:轻量进程支撑百万级并发、无锁并发模型、进程独立隔离、调度高效,完美适配网关、IM、游戏服务等长连接高并发场景。2、Erlang进程消息机制原理是什么?消息队列有什么特点?参考答案:所有Erlang进程通信均依赖消息传递,无共享内存,彻底规避锁竞争。原理:进程之间通过send发送消息,消息存入目标进程的私有消息队列,进程通过receive主动读取队列消息。消息队列核心特点:队列有序:消息先进先出,保证消息时序;读取可匹配:receive支持模式匹配,只处理匹配的消息,不匹配的消息会留在队列中,不会丢失;异步通信:发送消息无阻塞,无需等待对方处理完成。坑点:如果长期存在大量不匹配消息堆积,会导致进程内存持续上涨,引发内存泄漏,业务中必须定期清理或全量消费消息。3、什么是进程邮箱膨胀?如何解决?参考答案:进程邮箱膨胀就是消息队列堆积过多消息。常见场景:进程处理消息速度慢、receive匹配范围过窄、大量无效消息持续推送,导致未处理消息不断积压。危害:进程内存飙升、GC频繁、业务响应变慢,严重时导致服务卡死。解决方案:优化receive匹配逻辑,兜底处理无效消息,避免堆积;拆分进程职责,单进程不要承载过多消息处理逻辑;定时清空冗余消息,或设置消息处理超时;控制上游消息推送频率,避免消息洪泛。4、link和monitor的区别?各自使用场景?参考答案:两者都是进程监控机制,用于感知进程退出状态,核心区别在联动机制和使用场景。1)link(双向链接)双向绑定,AlinkB后,双方互相感知退出;默认带崩溃传播:一方异常崩溃,会直接连带另一方崩溃;场景:父子进程强绑定、核心服务联动,必须同启同停的进程。2)monitor(单向监控)单向监听,AmonitorB,仅A感知B的状态,B不感知A;无崩溃传播,B崩溃仅给A发送DOWN消息,不会影响A运行;场景:通用进程保活、临时进程监控、异步任务监听,是业务最常用的监控方式。四、OTP框架核心(中级/高级核心)1、简述OTP设计思想和核心组件参考答案:OTP是Erlang通用服务设计规范和库,不是独立框架,核心思想是标准化进程生命周期、容错、热更、监控,让所有服务遵循统一规范,避免手写裸进程带来的稳定性问题。核心组件:gen_server:通用同步/异步服务进程,业务核心载体,处理请求、维护状态;supervisor:进程监控树,负责进程启停、重启策略、故障容错;gen_event:事件驱动管理器,用于事件订阅、回调通知;gen_fsm/gen_statem:状态机服务,处理有状态流转的业务;application:应用打包与启停管理,实现服务模块化部署。2、gen_server的生命周期和核心回调函数作用参考答案:完整生命周期:启动初始化->循环处理消息->停止销毁核心回调:init/1:进程启动初始化,初始化状态、资源、配置,返回初始进程状态;handle_call/3:处理同步请求,客户端阻塞等待返回结果,适用于查询、强一致性操作;handle_cast/2:处理异步请求,客户端发送后立即返回,不等待结果,适用于日志、推送、非核心操作;handle_info/2:处理原生进程消息,如定时器、退出信号、自定义异步消息;terminate/2:进程退出前执行,用于释放资源、关闭连接、持久化数据;code_change/3:热更新回调,实现不停机代码升级、状态兼容。3、supervisor重启策略有哪些?分别适用场景?参考答案:supervisor提供四种标准重启策略,控制子进程崩溃后的重启逻辑:one_for_one:单个子进程崩溃,仅重启当前故障进程,其他进程不受影响,最常用,适用于独立业务子进程;one_for_all:单个子进程崩溃,重启所有子进程,适用于进程强依赖、必须整体存活的集群服务;rest_for_one:重启故障进程及后续启动的所有进程,适用于有启动顺序依赖的链式服务;simple_one_for_one:动态批量启动同类子进程,适用于连接池、会话进程、临时任务进程。同时可配置最大重启次数和时间窗口,防止进程反复崩溃无限重启,拖垮服务。4、gen_servercall和cast的核心区别?业务如何选型?参考答案:核心区别:call是同步阻塞调用,客户端发送请求后阻塞等待服务端返回结果,有超时机制;cast是异步非阻塞调用,客户端发送请求后立即返回,不等待执行结果,无返回值。业务选型:用call:需要获取执行结果、强一致性、查询数据、修改核心状态的场景;用cast:无需返回结果、容忍执行失败、高吞吐推送、日志统计、异步通知场景。注意:call超时会直接报错,高并发场景大量长耗时call会造成客户端阻塞堆积,需谨慎使用。五、性能与调优、踩坑实战(高级)1、Erlang常见内存泄漏场景和排查思路参考答案:常见泄漏场景:进程邮箱消息堆积,未消费的消息持续占用内存;ETS表无限写入数据,未定时清理、未设置过期;进程状态持续累加数据,未做清空和裁剪;监控、链接未及时解除,残留进程、僵尸进程占用资源;二进制大文件数据挂在进程状态中,无法被GC回收。排查思路:通过erlang:memory/0查看整体内存占用;通过recon、observer工具定位高内存进程、大二进制、堆积消息;排查ETS表数据量、过期策略、写入频率;检查进程生命周期,是否存在只创建不销毁的进程。2、ETS表的四种类型及适用场景参考答案:ETS是Erlang高频内存存储组件,用于进程间共享数据,四种核心类型:set:默认类型,键唯一,覆盖写入,适用于普通键值存储、配置缓存;ordered_set:按键有序排列,支持范围查询,适用于排序数据、有序列表场景;bag:键可重复,值不重复,同一键可存储多条不同数据;duplicate_bag:键和值均可重复,完全允许重复数据,适用于日志记录、事件统计。同时支持public/private/protected权限,高并发读场景优先public共享表,减少进程数据拷贝。3、Erlang热更新的原理和注意事项参考答案:热更新原理:ErlangVM支持同时加载模块的新旧两个版本,旧模块维持旧进程运行,新请求、新进程使用新模块,通过code_change回调完成进程状态兼容,实现不停机升级。注意事项:必须保证新旧状态兼容,code_change中要做状态格式适配,避免升级后进程卡死;不支持修改函数参数个数、删除核心回调,会导致新旧版本不兼容;热更后需手动回收旧模块,避免模块残留占用内存;复杂业务尽量小步迭代热更,避免大批量逻辑变更引发未知问题。4、如何解决Erlang进程调度卡顿(scheduler卡顿)参考答案:调度卡顿核心原因:单个进程长时间占用调度器,不主动让出时间片,导致其他进程无法调度。常见诱因:超长循环、超大批量同步计算、正则匹配卡死、死循环逻辑。解决方案:大任务拆分分片执行,每轮处理少量数据,主动让出调度时间片;耗时计算单独拆分独立进程,不阻塞核心服务进程;优化正则、字符串处理逻辑,避免高危耗时操作;调整虚拟机调度参数,绑定CPU核心,优化调度策略。六、面试高频手写代码题1、手写尾递归求和函数:计算1~N累加和参考答案:erlang

sum(N)->

sum(N,0).

sum(0,Res)->Res;

sum(N,Res)whenN>0->

sum(N-1,Res+N).解析:通过第二个参数缓存结果,最后一步仅递归调用,无后续计算,标准尾递归,内存恒定。2、手写简单gen_server模板(最简可用版本)参考答案:erlang

-module(demo_server).

-behaviour(gen_server).

-export([start_link/0]).

-export([init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2,code_change/3]).

start_link()->

gen_server:start_link({local,?MODULE},?MODULE,[],[]).

init([])->

{ok,#{}}.

handle_call(get_state,_From,State)->

{reply,{ok,State},State};

handle_call(_Request,_From,State)->

{reply,ok,State}.

handle_cast({set_key,K,V},State)->

NewSt

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论