多核OCaml – 2021年将会发生什么

2020-12-11 07:35:02

多核OCaml重叠执行A B A C B时间同时执行A B C时间

多核OCaml重叠执行A B A C B时间同时执行A B C时间效果处理程序

多核OCaml重叠执行A B A C B时间同时执行A B C时间效果处理程序域

在编写时没有并发性和并行性✦重构顺序代码本身的成本令人望而却步

在编写时就没有并发和并行的问题✦重构顺序代码本身的成本高昂•低延迟和可预测的性能✦非常适合要求约10ms延迟的应用程序

在编写时就没有并发和并行的问题sequential重构顺序代码本身的成本高昂•低延迟和可预测的性能✦非常适合要求约10ms延迟的应用程序•与调试和配置工具s gdb,lldb,性能,libunwind等

在编写时就没有并发和并行的问题sequential重构顺序代码本身的成本高昂•低延迟和可预测的性能✦非常适合要求约10ms延迟的应用程序•与调试和配置工具s gdb,lldb, perf,libunwind等。可伸缩性之前向后兼容

现有代码•性能向后兼容✦现有程序仅使用相同的内存就可以以同样的速度运行

现有代码•性能向后兼容✦现有程序仅使用相同的内存就可以以同样的速度运行•多核可伸缩性之前的GC延迟

现有代码•性能向后兼容✦现有程序仅使用相同的内存就可以以同样的速度运行•多核可伸缩性之前的GC延迟•与程序检查工具的兼容性

现有代码•性能向后兼容✦现有程序使用相同的内存运行速度一样快•多核可伸缩性之前的GC延迟•与程序检查工具的兼容性•高效的并发和并行编程抽象

—映射到操作系统威胁d✦建议每个内核有1个域

—映射到OS威胁d✦建议每个内核具有1个域•低级域AP I✦Spawn&加入,等待和if✦域本地存储✦原子存储操作✤Dolan等人,“时空上的数据竞争”,PLDI’18

—映射到OS威胁d✦建议每个内核具有1个域•低级域AP I✦Spawn&加入,等待和if✦域本地存储✦原子存储操作✤Dolan等人,“时空上的数据竞争”,PLDI’18•在域s之间共享对象没有限制✦但是它是如何工作的?

增量标记扫频GC次要堆主要堆•小(默认为2 MB)•凹凸指针分配•将幸存者复制到主要堆

增量标记扫频GC次要堆主要堆•小(默认为2 MB)•凹凸指针分配•将幸存者复制到主要堆中

增量,标记和清除GC次要堆主要堆•小(默认为2 MB)•凹凸指针分配•将幸存者复制到主要堆Mutator主循环开始空闲标记根标记根

分代,不移动,增量,标记清除的GC次要堆主要堆•小(默认为2 MB)•凹凸指针分配•幸存者已复制到主要堆中Mutator主要周期的开始空闲标记根标记根

GC•分代,不移动,增量,标记清除的GC次要堆主要堆•小(默认为2 MB)•凹凸指针分配•幸存者已复制到主要堆中Mutator主要循环的开始空闲标记根标记根

GC•世代的,不可移动的,增量的,标记清除的GC次要堆主要堆•小(默认为2 MB)•凹凸指针分配•幸存者已复制到主要堆中主循环结束Mutator主循环开始空闲标记根标记根

GC•世代的,不可移动的,增量的,标记清除的GC次要堆主要堆•小(默认为2 MB)•凹凸指针分配•幸存者已复制到主要堆中主循环结束Mutator主循环开始空闲标记根标记根•快速分配

GC•世代的,不可移动的,增量的,标记清除的GC次要堆主要堆•小(默认为2 MB)•凹凸指针分配•幸存者已复制到主要堆中主循环结束Mutator主循环开始空闲标记根标记根•快速分配•最大GC延迟< 10毫秒,第99个百分位数延迟< 1毫秒

Dom 1 Dom 0 Dom 1域0分配指针域1分配指针次堆

次要hea p✦2个全局障碍/次要g c✦在24个内核上,〜10 ms的暂停主要堆Dom 0 Dom 0 Dom 1 Dom 0 Dom 1域0分配指针域1分配指针次堆

without所有标记和清扫工作都没有同步完成per每个周期3个屏障(最坏的情况),以同意GC阶段s的结束✤OCam中的两种纤芯的2个屏障✦〜5毫秒在24个核上暂停标记根mutator扫描标记根主要周期的开始主要周期的标记和扫描阶段的末尾可能重叠域0域1

库存(正常运行时间的几何数)measurement测量噪声下的差异最多y分配器上的差异导致的离群值

编译器级别太低•Domainslib-https://github.com/ocaml-multicore/domainslib Domain 0 Domain N…Task Pool Async / Await Parallel for Domainslib

编译器级别太低•Domainslib-https://github.com/ocaml-multicore/domainslib Domain 0 Domain N…Task Pool Async / Await为Domainslib并行让我们来看示例!

= let res中的T.setup_pool〜num_domains:(num_domains-1)= T.teardown_pool池中的fib_par池n; res模块T = Domainslib.Task

= let res中的T.setup_pool〜num_domains:(num_domains-1)= T.teardown_pool池中的fib_par池n; res let rec fib_par池n =如果n< = 40则fib_seq n否则让a = T.async池(fun_-> fib_par池(n-1))在let b = T.async池(fun _- > T.await池a + T.await池b模块中的fib_par池(n-2))T = Domainslib.Task

n < 2然后1个其他fib_seq(n-1)+ fib_seq(n-2)let fib n = let pool = T.setup_pool〜num_domains:(num_domains-1)in let res = T.teardown_pool pool中的fib_par pool n; res let rec fib_par池n =如果n< = 40则fib_seq n否则让a = T.async池(fun_-> fib_par池(n-1))在let b = T.async池(fun _- > T.await池a + T.await池b模块中的fib_par池(n-2))T = Domainslib.Task

自我1 37.787 0.98 1 2 19.034 1.94 1.99 4 9.723 3.8 3.89 8 5.023 7.36 7.52 16 2.914 12.68 12.97 24 2.201 16.79 17.17

x = 0等于board_size-1做y = 0等于board_size-1做next_board。(x)。(y)<-next_cell cur_board x y完成; ...

x = 0等于board_size-1做y = 0等于board_size-1做next_board。(x)。(y)<-next_cell cur_board x y完成; ...让next()= ... T.parallel_for pool〜start:0〜finish:(board_size-1)〜body:(fun x-> for y = 0 to board_size-1 do next_board。(x) 。(y)<-next_cell cur_board xy完成); ...

自身1 24.326 1 1 2 12.290 1.980 1.98 4 6.260 3.890 3.89 8 3.238 7.51 7.51 16 1.726 14.09 14.09 24 1.212 20.07 20.07电路板尺寸= 1024,迭代= 512

OCam中的编程库with具有更好语法的面向回调的编程并行是一种性能hack,而并发是一种程序结构机制

OCam中的编程库✦具有更好的语法的面向回调的编程•遭受面向回调的程序的许多陷阱min✦没有回溯,不能使用异常,monadic语法并行性是一种性能hack,而并发是一种程序结构机制

OCam中的编程库✦具有更好的语法的面向回调的编程•遭受面向回调的程序的许多陷阱•back没有回溯,无法使用异常,单语法的语法•Go(goroutines)和GHC Haskell(线程)具有更好的抽象—轻量级线程并行是一种性能hack,而并发是一种程序结构机制

OCam中的编程库✦具有更好的语法的面向回调的编程•遭受面向回调的程序的许多陷阱•back没有回溯,无法使用异常,单语法的语法•Go(goroutines)和GHC Haskell(线程)具有更好的抽象—轻量级线程并行性是一种性能突破,而并发则是一种程序结构化机制是否应该向OCaml添加轻量级线程?

固定效果•非本地控制流机制的模块化基础✦异常,生成器,轻量级线程,promise,异步IO,协程

固定效果•非本地控制流机制的模块化基础✦异常,生成器,轻量级线程,promise,异步IO,协程•效果声明与解释分开(参见c.f.异常)

定义的效果•非本地控制流机制的模块化基础✦异常,生成器,轻量级线程,promise,异步IO,协程•效果声明与解释(cf异常)分开效果E:字符串let comp()= print_string " 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4"

定义的效果•非本地控制流机制的模块化基础✦异常,生成器,轻量级线程,promise,异步IO,协程•效果声明与解释(cf异常)分开效果E:字符串let comp()= print_string " 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4"效果声明

定义的效果•非本地控制流机制的模块化基础✦异常,生成器,轻量级线程,promise,异步IO,协程•效果声明与解释(cf异常)分开效果E:字符串let comp()= print_string " 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4"计算效果声明

定义的效果•非本地控制流机制的模块化基础✦异常,生成器,轻量级线程,promise,异步IO,协程•效果声明与解释(cf异常)分开效果E:字符串let comp()= print_string " 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4"计算处理程序效果声明

定义的效果•非本地控制流机制的模块化基础✦异常,生成器,轻量级线程,promise,异步IO,协程•效果声明与解释(cf异常)分开效果E:字符串let comp()= print_string " 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4"计算处理程序暂停当前的计算效果声明

定义的效果•非本地控制流机制的模块化基础✦异常,生成器,轻量级线程,promise,异步IO,协程•效果声明与解释(cf异常)分开效果E:字符串let comp()= print_string " 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4"计算处理程序定界的延续暂停当前的计算效果声明

定义的效果•非本地控制流机制的模块化基础✦异常,生成器,轻量级线程,promise,异步IO,协程•效果声明与解释(cf异常)分开效果E:字符串let comp()= print_string " 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4"计算处理程序定界的连续中止当前计算恢复中止计算效果声明

()= print_string" 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4"个人电脑

()= print_string" 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4"个人电脑

comp()= print_string" 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4" pc主sp父光纤:一块堆栈+效果处理程序

让comp()= print_string" 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4" pc主sp父0

让comp()= print_string" 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4" pc主sp k 0

让comp()= print_string" 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4" pc主sp k 0

让comp()= print_string" 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4" pc主sp k 0

让comp()= print_string" 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4" pc main sp k 0 1

让comp()= print_string" 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4" pc main sp k 0 1

让comp()= print_string" 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4" pc主sp k父0 1

让comp()= print_string" 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4" pc main sp k父级0 1 2

()= print_string" 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4" pc main sp k 0 1 2 3

()= print_string" 0&#34 ;; print_string(执行E); print_string" 3"让main()=尝试comp()的效果E k-> print_string" 1&#34 ;;继续k" 2&#34 ;; print_string“ 4" pc main sp k 0 1 2 3 4

效果收益率:unit let run main = ...(*假定连续队列*)let run_next()=将出队()与|匹配。一些k->继续k()|无-> ()中的rec rec生成f =将f()与|匹配。 ()-> run_next()|效果产量k->排队k; run_next()|效果(叉f)k->排队k;在主生成中生成f

效果收益率:unit let run main = ...(*假定连续队列*)let run_next()=将出队()与|匹配。一些k->继续k()|无-> ()中的rec rec生成f =将f()与|匹配。 ()-> run_next()|效果产量k->排队k; run_next()|效果(叉f)k->排队k;生成主生成中的f,让fork f =执行(Fork f)let yield()=执行Yield

print_endline" 1.a&#34 ;;让 (); print_endline" 1.b");叉(fun _-> print_endline" 2.a&#34 ;; yield(); print_endline“ 2.b");;主跑

print_endline" 1.a&#34 ;;让 (); print_endline" 1.b");叉(fun _-> print_endline" 2.a&#34 ;; yield(); print_endline“ 2.b");;运行主1.a 2.a 1.b 2.b

print_endline" 1.a&#34 ;;让 (); print_endline" 1.b");叉(fun _-> print_endline" 2.a&#34 ;; yield(); print_endline“ 2.b");;运行main 1.a 2.a 1.b 2.b•直接样式(无monad)•用户代码无需了解效果

产生值s JavaScript JavaScript和Pytho n中的基元✦可以使用效果处理程序从迭代器中自动派生

产生值s JavaScript JavaScript和Pytho n中的基元✦可以使用效果处理程序从迭代器自动派生•任务-遍历深度为2的完整二叉树✦226个堆栈开关

产生值s JavaScript JavaScript和Pytho n中的基元✦可以使用效果处理程序从迭代器自动派生•任务-遍历深度2的完整二叉树5✦226个堆栈开关•迭代器-惯用递归遍历

产生值s JavaScript JavaScript和Pytho n中的基元✦可以使用效果处理程序从迭代器自动派生•任务-遍历深度为2的完整二叉树5✦226个堆栈开关•迭代器-惯用的递归遍历•生成器✦手写的生成器(hw-generator)✤CPS转换+去功能化以消除中间闭合分配n effect使用效果处理程序的生成器(eh-generator)

(3.76x)eh生成器1879(9.30x)多核OCaml变体时间(毫秒)迭代器(基线)492生成器43842(89.1x)nodejs 14.07

e✦https://github.com/kayceesrk/ocaml-aeio/•变体s✦Go + net / http(GOMAXPROCS = 1)✦OCaml + http / af + Lwt(显式回调)✦OCaml + http / af +效果处理程序(MC)•使用wrk2衡量的性能

e✦https://github.com/kayceesrk/ocaml-aeio/•变体s✦Go + net / http(GOMAXPROCS = 1)✦OCaml + http / af + Lwt(显式回调)✦OCaml + http / af +效果处理程序(MC)•使用wrk2衡量的性能

e✦https://github.com/kayceesrk/ocaml-aeio/•变体s✦Go + net / http(GOMAXPROCS = 1)✦OCaml + http / af + Lwt(显式回调)✦OCaml + http / af +效果处理程序(MC)•使用wrk2衡量的性能•直接样式(无monadic语法)

rst 2.对效果处理程序的运行时支持•没有效果语法,但其中的所有编译器和运行时位

rst 2.效果处理器的运行时支持•没有效果语法,但3.效果系统中的所有编译器和运行时位。跟踪典型值中用户定义的效果。在典型值c中跟踪ambinet效果(参考,IO)。 OCaml成为纯语言(在Haskell意义上)。

rst 2.效果处理器的运行时支持•没有效果语法,但3.效果系统中的所有编译器和运行时位。跟踪典型值中用户定义的效果。在典型值c中跟踪ambinet效果(参考,IO)。 OCaml成为纯语言(在Haskell意义上)。让foo()= print_string" hello,world" val foo:unit-[io]->单元语法仍在开发中

资助多核OCaml开发! •多核+ Tezo✦并行Lwt抢占任务✦直接样式异步IO库✤桥接Async和Lw t之间的差距✦并行Irmin(Tezos的存储层) 资助多核OCaml开发! •多核+ Tezo✦并行Lwt抢占任务✦直接样式异步IO库✤桥接Async和Lw t之间的差距✦并行Irmin(Tezos的存储层)•端到端多核Tezos演示器(2021年中) ) — https://github.com/ocaml-multicore/effects-示例•Sivaramakrishnan等人,“并行化到OCaml的并行化”,ICFP 2020 ......