3

According to the doumentation for Control.Parallel, one should make sure that the computation being sparked is non-trivial so that creating the spark is cheaper than the computation itself.

This makes sense, but after listening to Bartosz Milewski talk about how cheap sparks are, I'm wondering how experienced Haskell programmers determine whether or not a computation is worthy of parallelism.

4

1 回答 1

0

这个主题是事实,而不是基于意见。

在阅读之前,请注意有关实际间接费用的一些事实

".. 创建 spark不会立即唤醒空闲能力,请看这里。默认调度间隔是 20ms,所以当你创建 spark 时,最多需要 20ms 才能将其转换为真正的线程。到那时调用线程很可能已经评估了thunk,并且火花将被GC或失败。

相反,forkIO如果有空闲功能,将立即唤醒。这就是为什么显式并发比并行策略更可靠的原因。”

forkIO因此,请记住在实际可实现的成本/收益(加速)公式中将 +20 毫秒和/或生成的功能块的基准成本添加到下面引用的附加开销中。


几十年前,Gene AMDAHL 博士解决了这个问题

最近几代的 C/S 学生或实践者似乎忘记了基本的进程调度逻辑(即在系统受限的物理资源上正确组织代码执行流的规则,而不是艺术)。

尽管一个公平的反对意见可能并且将会来自函数式语言的性质,其中 lambda 演算可以而且经常确实利用一个空间,否则对于命令式语言来说是隐藏的,用于进入一个智能的、细粒度的并行性,从lambda- 或 pi- 微积分定律。

然而,核心信息已经存在并且已经存在了 60 多年。


一个定量的,公平的,基于证据记录的理由就足够了:(没有魔法,没有任何性质的隐藏艺术)

请先尽力先充分理解阿姆达尔定律的原始表述,另外还请修改最近对原始、普遍有效、通用系统的批评和开销-严格、资源意识的重新表述-调度规律。

[批评] 部分中的添加是为了与实际发生的情况完全匹配,当有人想到一段代码时,想“重新组织”计算图并进入流程流程,或者“只是” -[CONCURRENT]或真正[PARALLEL]的计算语法构造函数(无论实际的代码执行工具是什么)。


得到了开销严格的阿姆达尔定律理论,让我们测量一下:

这部分简单而系统:我的学生经常咆哮,但接下来,他们每个人都收集了一组实践经验,实际需要什么(成本)来实现使用并行代码执行的任何形式的承诺.

1)创建一个 NOP 函数 - 一个函数,除了运行(没有义务传递任何内容之外,实际上什么都不做,在体积、参数方面越少,也没有尝试在其(空)-code-execution 并且不返回任何值 "back" )。这是一个理想化的 NOP 功能有效负载,让它被生成/激发/分发到并行工具选择驱动的执行中。

准备好 NOP-fun,让我们在多个实例中对这种 NOP-fun 代码执行的纯开销进行基准测试,并测量它所花费的时间。

确保所有此类实例确实“在那里”没有做任何事情,两条时间线之间花费的时间总和是 - 万岁 - 并行化的纯开销成本和流程重新收集开销成本。

如此简单,如此容易。

不同的工具在用户程序将产生多少成本方面有所不同,但指标和方法都非常清楚。

 CuT_start <- liftIO $ getCurrentTime  -- a Code_Under_Test___START
                                       -- I use a ZeroMQ Stopwatch() instance
                                       -- having a better than [us] resolution
                                       -- but haven't found it in Haskell binding
 --CuT_TIMING_CRITICAL_SECTION_/\/\/\/\/\/\\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
 <_CuT_a_Code_syntax-constructor_Under_Test_>
 --CuT_TIMING_CRITICAL_SECTION_/\/\/\/\/\/\\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\

 CuT_end <- liftIO $ getCurrentTime    -- a Code_Under_Test___END

 liftIO $ print ( diffUTCTime CuT_end CuT_start )

2)已经记录了产生/触发预期数量的作业的净成本,可以转发:
- 添加“远程”内存分配(字面意思是直到交换杀死O / S)
- 添加“远程” CPU绑定处理(再一次,就人们闻到 O/S 内核调度工作的疲劳来创建一些但可行的硬件线程映射)
- 根据调用接口缩放添加“远程”进程测试(需要通过的数据量从调用者到被调用者)依赖项
- 添加“远程”进程返回值
- 添加“远程”进程需要访问某些共享资源


最终决定 Go - No Go :

所有这些,上述收集和记录的附加成本,只会增加现实世界的代码开销成本,必须将其纳入最近重新制定的阿姆达尔定律

当且仅当
开销严格、资源感知的加速结果为>> 1.00时,才有意义进入并行代码执行

在所有情况下,
改进的”加速实际上<= 1.00,支付多于从这种“改进”中获得的收益确实是一个非常糟糕的主意

(一个相反的公式总是可能的 - 导出最少的处理量,这将至少证明上述使用相应类型的并行代码语法构造器的系统基准成本是合理的)

量子点

于 2017-12-10T23:59:26.673 回答