个人读书笔记,我看书走马观花,侧重点比较诡异,大多流水记录,可读性不大。

入门

  • erl shell,执行最后要加个 .
  • 变量不变, 强制大写开头
  • = 表示模式匹配,不是常规语言中的赋值
    • 变量多次赋值,就会exception error: no match of right hand side value
  • 抛弃副作用,拥抱并行化
  • erlang中原子,表示非数字常量 (很诡异的歧义,注意)
    • 小写字母开头可以用_@连接
  • 每个表达式都必须有值
  • 元组与元组展开。和python c++类似
  • 列表,以及列表头尾快捷操作(有点像模板元)
  • 字符串
    • 就是整数列表,必须双引号,需要大写字母开头
    • $i表示字符i

顺序型编程

  • 一切都是表达式,一切表达式都有值

    • 所以说ruby perl rust那种最后留一个值做返回值的做法算是函数式风格的求值?
  • 模块 和python/js类似 ,-module(module_name) -export(func_name) 导出 -import(module_name, [func_name])
  • 函数
    • 同名不同目,也就是重载支持,可以,只做helper
    • func,也就是lambda,支持作为参数以及返回
  • 控制流对应成匹配,循环,那就用列表生成
  • if/case都是case模式匹配

  • 异常

    • try-catch 也是case模式的,丢失细节
    • erlang:error
    sqrt(X) when X < 0 ->
        erlang:error({squareRootNegativeArgument, X});
    sqrt(X) ->
        math:sqrt(X)
    

    有点像c++ 的constraint

  • 调用栈

    • erlang:get_stacktrace()
  • BIT 内建函数 buildin

    • tuple_to_list
    • 二进制流 «“cat”»
  • 属性-SomeTag()

  • 块表达式,begin end包起来整体求值

  • 宏,引用,这套和c有点像

  • 进程字典,每个进程有自己的私有数据

    • 运行时别用。当成元数据保存还行
  • 引用,全局唯一的值。有点像全局变量。

  • 下划线变量 用完就扔,调试用

编译运行

  • 指定搜索路径

    @spec code:add_patha(Dir) => true |{error, badd_directory}
    @spec code:add_pathz(Dir) => true |{error, badd_directory}
    
  • 编译运行与脚本运行

    • 脚本需要main入口,编译直接调用函数就行
    • 也得写makefile(2020了还手写吗)

并发

  • 并发原语

    • spawn启动一个进程,返回pid

    • a ! b表示发送

    • receive 可以带超时限制
      • 同步?
    • 进程管理 -> 注册进程

    • 一个echo

      start() ->
          spawn(fun() -> loop([]) end).
          
      rpc(Pid, Request) ->
          Pid ! {self(), Request},
          receive
              {Pid, Response} ->
                  Response
          end.
          
      loop(X) ->
          receive
              Any ->
                  io:format("Received:~p~n", [Any]),
                  loop(x)
          end.
      
      • 用到了尾递归技术,不能有多余的函数调用,不然不能复用栈空间、
  • MFA 启动进程, spawn(Mod, FuncName, Args) 动态更新升级?

并发编程中的错误处理

  • 链接进程

    进程依赖的强绑定,强制信号通知,这些东西在c是不强制的

  • on_exit 这东西c++也有,erlang的on_exit还可以hook已有 的进程,很妙

  • 天生分布式,进程的错误托管给别的进程来处理

  • 错误处理的三种基础盖面

    • 进程链接
    • 退出信号
    • 系统进程信息
  • 捕获退出的编程模式

    • 不在乎进程是否崩溃 Pid = spawn(func() -> ...end)
    • 进程崩溃我也崩溃,进程链接 Pid = spwan_link(fun() -> ...end)
    • 进程崩溃我处理错误

       ...
       process_flag(trap_exit, true),
       Pid = spwan_link(fun() -> ...end),
       ...
       loop(...).
      

    loop(State) -> receive {‘EXIT’, SomePid, Reason} -> %% do something with the error loop(State); … end

      
    
  • 错误处理原语

    • spawn_link
    • process_flag
    • link
    • unlink
    • exit
  • 工人-监工模型

  • monitor,守护进程

    keep_alive(Name, Fun) ->
      register(Name, Pid = spawn(Fun)),
      on_exit(Pid, fun(_Why) -> keep_alive(Name, Fun) end).
    

分布式编程

  • rpc
  • global名称注册函数/分布式锁定功能
  • cookies设置

基于socket

接口技术

  • open_port

文件编程

没啥说的

套接字编程

没啥说的

ETS/DETS

OTP

监控树和supervisor

多核问题

  • 状态不可变,并行化
  • MapReduce

更有效率

  • 大量进程 但不要太多
  • 避免副作用
  • 避免顺序瓶颈
  • 少量消息,大量计算

ref

  1. 关于erlang进程系统的资料

    1. https://www.iteye.com/blog/jzhihui-1482175
    2. https://www.erlang-factory.com/upload/presentations/558/efsf2012-whatsapp-scaling.pdf
    3. https://blog.yufeng.info/archives/2615
    4. https://www.zhihu.com/question/24732869
  2. 希望能看懂https://github.com/cbd/edis/blob/master/src/edis_sup.erl

  3. https://www.cnblogs.com/me-sa/ 这人写的erlang博客不错,讲真看这本书不如看他的博客