Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Parallel processing 什么时候可以并行使用可变变量调用函数?_Parallel Processing_F#_Mutable - Fatal编程技术网

Parallel processing 什么时候可以并行使用可变变量调用函数?

Parallel processing 什么时候可以并行使用可变变量调用函数?,parallel-processing,f#,mutable,Parallel Processing,F#,Mutable,在看了菲尔·特雷福德(Phil Trelford)有趣的演讲后 我对用数组替换列表以及更一般地使用可变变量来加速代码的可能性很感兴趣。所以我做了一个简单的测试: let xs = [0.0..1000000.00] let axs = List.toArray xs let f x = sin (x * x) List.map f xs // Real: 00:00:00.170, CPU: 00:00:00.187, GC gen0: 5, gen1: 3, gen2: 1 Array

在看了菲尔·特雷福德(Phil Trelford)有趣的演讲后

我对用数组替换列表以及更一般地使用可变变量来加速代码的可能性很感兴趣。所以我做了一个简单的测试:

let xs = [0.0..1000000.00]
let axs = List.toArray xs

let f x = sin (x * x)

List.map f xs // Real: 00:00:00.170, CPU: 00:00:00.187, GC gen0: 5, gen1: 3, gen2: 1

Array.map f axs // Real: 00:00:00.046, CPU: 00:00:00.046, GC gen0: 0, gen1: 0, gen2: 0
通过数组映射比通过列表映射快三倍多。在这一点上,我还没有测试调用的函数计算量更大时的速度差。这种差异可能仅仅是因为在数组中的项之间移动更快,并且当每次迭代都是计算密集型的时,这种差异可能变得无关紧要

不过,在某些情况下,使用数组或更普遍的可变变量可能会产生显著的差异

在将代码更改为使用数组而不是列表之前,我希望更清楚地了解代码并行化的后果


一般来说,何时可以使用可变变量而不冒并行化代码出现问题的风险?有没有一个简单的测试可以让我确定并行调用时函数的健壮性?

数组的速度差与易变性无关;都是关于你的。数组在内存中是连续的,因此它们的迭代速度比列表快:F#列表是单链接列表,因此每个项可以(通常是)位于不同的内存位置。这意味着您不会从CPU的缓存中受益,而对于阵列,一旦您支付了从内存中检索第一个项目的费用,那么第二个到第N个项目(其中N的值取决于您正在检索的项目的大小)就已经在缓存中,并且可以随时进行检索。如果F#有一个ImmutableArray类,并且您使用了它,那么在通过该ImmutableArray进行映射时,您将获得与从可变数组进行映射时相同的速度优势

至于您的主要问题,关于在并行代码中使用可变变量何时是安全的,简单的测试是问“我真的在改变多个线程正在使用的数据吗?”如果您没有改变数据,那么让多个线程并行访问它是安全的。即使数据可能会发生变异(例如,数组),只要您实际上没有对其进行变异,那么您的并行代码就不会遇到问题。如果确实要对数据进行变异,那么就必须处理锁定,以及锁定带来的所有问题,如资源匮乏、死锁等


因此,简单的经验法则是“变异数据+并行度=痛苦”。如果您改变了数据,但没有运行并行代码,那么您的痛苦就会小得多。如果您不改变数据,那么并行代码就不会给您带来痛苦。但是如果你同时做这两件事,那就要做好头痛的准备。

阵列的速度差异与可变性无关;都是关于你的。数组在内存中是连续的,因此它们的迭代速度比列表快:F#列表是单链接列表,因此每个项可以(通常是)位于不同的内存位置。这意味着您不会从CPU的缓存中受益,而对于阵列,一旦您支付了从内存中检索第一个项目的费用,那么第二个到第N个项目(其中N的值取决于您正在检索的项目的大小)就已经在缓存中,并且可以随时进行检索。如果F#有一个ImmutableArray类,并且您使用了它,那么在通过该ImmutableArray进行映射时,您将获得与从可变数组进行映射时相同的速度优势

至于您的主要问题,关于在并行代码中使用可变变量何时是安全的,简单的测试是问“我真的在改变多个线程正在使用的数据吗?”如果您没有改变数据,那么让多个线程并行访问它是安全的。即使数据可能会发生变异(例如,数组),只要您实际上没有对其进行变异,那么您的并行代码就不会遇到问题。如果确实要对数据进行变异,那么就必须处理锁定,以及锁定带来的所有问题,如资源匮乏、死锁等


因此,简单的经验法则是“变异数据+并行度=痛苦”。如果您改变了数据,但没有运行并行代码,那么您的痛苦就会小得多。如果您不改变数据,那么并行代码就不会给您带来痛苦。但是如果你同时做这两件事,准备好头疼。

虽然@ RMMN给实际问题提供了一个很好的答案,但我觉得我必须写这个补遗,因为我认为这很重要,而且太长了,无法适应评论。

这是为了回答一个隐含的问题,我将其理解为“既然可变数据更快,我不应该总是使用可变数据吗?”

事实上,通常情况下,可变数据结构(如果正确的话)在表面上速度更快,那么我们为什么不一直使用它们呢?如果正确的话,跳转也确实比函数调用快,那么为什么呢?当然,如果你做得对的话,手动内存管理会占用更少的内存,并且比垃圾收集更快,那么我们为什么要使用垃圾收集呢?而且(可以说)如果你真的,真的正确的话,直接用汇编语言,甚至二进制代码来编写要比编译快,这是事实,那么为什么我们有高级语言呢

以上所有问题的答案是,性能并不是软件开发中唯一关心的问题。这甚至不是最重要的问题。甚至可以说,它根本就不是最重要的关注点。在现代,更重要的是可读性、稳定性、可维护性和整体弹性

在设计系统时,首先尝试猜测瓶颈可能在哪里,然后仔细设计这些地方,并在其周围放置一些日志记录和工具。编写程序时,要使其可读,理解