C# 中的 lambda 表达式/委托是“纯粹的”吗?

问题描述 投票:0回答:5

最近询问关于没有副作用的函数式程序,并了解到这对于使并行任务变得微不足道意味着什么。具体来说,“纯”函数使这变得微不足道,因为它们没有副作用。

我最近也在研究 LINQ 和 lambda 表达式,因为我在 StackOverflow 上多次遇到涉及枚举的示例。这让我想知道现在在 C# 中并行化枚举或循环是否可以“更容易”。

lambda 表达式是否“纯粹”足以实现微不足道的并行化?也许这取决于你对表达式所做的事情,但它们足够纯粹吗?这样的事情在 C# 中理论上可能/微不足道吗?:

  • 将循环分成块
  • 运行一个线程来循环每个块
  • 运行一个函数,对来自的值执行某些操作 每个线程的当前循环位置

例如,假设我在游戏循环中有一堆对象(因为我正在开发游戏并正在考虑多线程的可能性)并且必须在每一帧对它们中的每个对象执行一些操作,上面的内容对于拔下来?看看 IEnumerable ,它似乎只跟踪当前位置,所以我不确定是否可以使用普通的通用集合将枚举分解为“块”。

很抱歉问这个问题。我在上面使用了项目符号而不是伪代码,因为我什至不知道如何随心所欲地编写伪代码。我的.NET知识纯粹是简单的业务知识,而且我对委托和线程等还很陌生。我主要想知道上述方法是否适合追求,以及委托/lambdas是否不必担心什么时候这涉及到它们的并行化。

c# .net functional-programming lambda
5个回答
18
投票

首先,请注意,为了“纯粹”,方法不仅必须没有副作用。当给定相同的参数时,它还必须始终返回相同的结果。因此,例如“Math.Sin”方法是纯方法。你输入 12,它就会返回 sin(12),而且每次都是一样的。即使 GetCurrentTime() 方法没有副作用,它也不是纯粹的;无论您传入什么参数,每次调用它都会返回不同的值。

还要注意,纯方法实际上不应该抛出异常;出于我们的目的,异常算作可观察到的副作用。

第二,是的,如果您可以推断方法的纯度,那么您可以做一些有趣的事情来自动并行化它。问题是,几乎没有方法实际上是纯粹的。此外,假设你确实有一个纯粹的方法;由于纯方法是记忆化的完美候选者,并且由于记忆化引入了副作用(它会改变缓存!),因此采用应该是纯方法的方法然后使它们变得不纯是非常有吸引力的。

我们真正需要的是某种方法来“抑制副作用”,正如乔·达菲所说。某种方法可以在方法周围画一个框,并说“这个方法不是没有副作用的,但它的副作用在这个框之外是不可见的”,然后使用that事实来驱动安全的自动并行化。

我很想找到一些方法将这些概念添加到 C# 等语言中,但这完全是蓝天开放研究问题的东西;没有任何有意或暗示的承诺。


13
投票

Lambda 的应该是纯净的。然后,FrameWork 通过简单的

.AsParallel
添加到 LINQ 查询 (PLINQ) 来提供自动并行化。

但这不是自动的或保证的,程序员有责任使/保持它们纯净。


3
投票

lambda 是否是纯的取决于它正在做什么。作为一个概念,它既不纯粹也不纯粹。

例如:以下 lambda 表达式是不纯的,因为它正在读取和写入主体中的单个变量。并行运行会产生竞争条件。

var i = 0;
Func<bool> del = () => {
  if ( i == 42 ) { return true; }
  else ( i++ ) { return false; }
};

相反,下面的委托是纯粹的并且没有竞争条件。

Func<bool> del = () => true;

3
投票

至于循环部分,您还可以使用

Parallel.For
Parallel.ForEach
作为有关游戏中对象的示例。这也是 .net 4 的一部分,但您可以下载它。


© www.soinside.com 2019 - 2024. All rights reserved.