简述
在某个需要的驱动下,心愿实现线程间共享的路由树。鉴于如下的外围需要:
- 读多写少,写入操作重,读取操作轻。
- 性能足够快,不心愿有单点。
鉴于有数据共享需要,没有单点的状况下,erlang 中简直只有 ets 了。因为 ets 仅能实现 k,v 查问,不能实现更简单的读写需要,比方寻找某个子网 (key=”192.168.x.x”) 下的任意 IP(values = [“192.168.1.1”, “192.168.2.3”]),于是决定用 NIF 来实现。这是第一次尝试在理论业务中应用 NIF。这里做一下总结。
实现时的考量
数据转换 erlang_term to c and c to erlang_term
大部分语言都提供 c 拓展,第一件事就是,如何把语言的内置类型转为 c 中的类型,以及如何将 c 中的数据结构转为语言的内置类型。
这里能够
- 间接应用 enif_get/enif_make 系列接口。
- 参考 https://github.com/goertzenat…,利用 c ++ template,在编译期主动依据类型开展雷同的 enif_get/enif_make 系列代码。
资源管理
参考 https://www.erlang.org/doc/ma…
次要有两种:
- 本人治理,比方将资源存储在动态变量中,提供 destroy_nif 之类,由用户销毁。
- erlang 治理,nif 不治理资源,erlang_term 复制进来后,由 erlang 的援用计数治理。
动静类型
能够用 enif_term_to_binary/enif_binary_to_term 系列接口,在同样的数据结构中存储动静的 erlang 构造。
线程平安
一般来说,nif 是在 erlang 的 scheduler 线程执行的。所以,须要用 enif_mutex/enif_rwlock 系列接口爱护资源,防止未定义的行为。也能够间接应用 c ++ 的 mutex,操作系统 api 等等。
如:https://en.cppreference.com/w…
调度器和上下文切换
erlang 调用 nif 是没有上下文切换的。那么就会有一个问题,如果 nif 始终占用 cpu 怎么办?如何偏心调度?
https://www.erlang.org/doc/ma…
nif 函数应该尽快(1ms 内)返回。否则,会导致一些异样行为,我遇到的状况是日志刷不进去(调度异样)。为防止这种状况,咱们须要更简单的策略如下。
协程化:
- 用 enif_consume_timeslice 看本人是否还有工夫片。
-
用 enif_schedule_nif yield to scheduler。
异步化:
另起 thread 计算,在用 enif_send 将后果发回去,这样不影响调度线程。
Dirty Nif:
其实就是官网的 worker thread,按 cpu/io bound 分类,防止影响一般调度器。
调试
占位。原理上,和一般 c 程序调试动静库没有太多区别。工作流倒是能够记录一下。
总结
- 没有银弹,nif 有其应用的场景:小音讯,大计算。
参考
- https://www.erlang.org/doc/ma…
- https://www.erlang.org/doc/tu…
- https://github.com/goertzenat…