在C#中lambda表达式/委托是“纯粹的”,还是可以?

时间:2010-03-17 22:21:35

标签: c# .net functional-programming lambda

I recently asked关于没有副作用的功能程序,并了解这对于使并行化任务变得微不足道意味着什么。具体来说,“纯粹”的功能使这一点变得微不足道,因为它们没有任何副作用。

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

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

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

例如,假设我在游戏循环中有一堆对象(因为我正在开发游戏并考虑多线程的可能性)并且必须每帧都对它们做一些事情,上面是拉扯琐碎?看看IEnumerable似乎它只跟踪当前的位置,所以我不确定我是否可以使用普通的泛型集合来将枚举分解为“块”。

对此问题感到抱歉。我使用上面的子弹而不是伪代码,因为我甚至不知道如何编写伪代码。我的.NET知识纯粹是简单的业务,我是代表和线程等的新手。我主要想知道上面的方法是否适合追求,如果代表/ lambdas不必担心什么时候它涉及到它们的并行化。

5 个答案:

答案 0 :(得分:17)

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

另请注意,纯方法确实不应该抛出异常;例外情况被视为我们目的的可观察副作用。

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

正如Joe Duffy所说,我们真正需要的是一种“驯服副作用”的方法。某种方法在方法周围绘制一个方框并说“此方法不是无副作用,但其副作用在此框外不可见”,然后使用 事实驱动安全的自动并行化。

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

答案 1 :(得分:13)

Lambda的应该是纯粹的。然后,FrameWork提供自动并行化,只需对LINQ查询(PLINQ)进行简单的.AsParallel添加。

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

答案 2 :(得分:3)

lambda是否纯粹与它正在做的事情有关。作为一个概念,它既不纯粹也不纯洁。

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

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

相反,以下代表是纯粹的,没有竞争条件。

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

答案 3 :(得分:3)

对于循环部分,您还可以使用Parallel.ForParallel.ForEach作为游戏中对象的示例。这也是.net 4的一部分,但你可以下载它。

答案 4 :(得分:2)

有13篇部分内容涉及.NET 4.0 here中新的Parallelism支持。它还包括对第7部分中LINQ和PLINQ的讨论。这是一个很好的阅读,所以请查看