C# 中的 lambda 表达式/委托是“纯粹的”吗?或者可以吗?
我最近询问函数式程序没有副作用,并了解了这对于使并行任务变得琐碎意味着什么。具体来说,“纯”函数使这变得微不足道,因为它们没有副作用。
我最近还在研究 LINQ 和 lambda 表达式,因为我在 StackOverflow 上多次遇到涉及枚举的示例。这让我想知道现在在 C# 中并行化枚举或循环是否可以“更容易”。
lambda 表达式是否“纯粹”足以实现微不足道的并行化?也许这取决于你对表达式所做的事情,但它们足够纯粹吗?这样的事情在 C# 中理论上可能/微不足道吗?:
- 将循环分成块
- 运行一个线程来循环每个块
- 运行一个函数,该函数对来自的值执行某些操作 每个线程的当前循环位置
例如,假设我在游戏循环中有一堆对象(因为我正在开发游戏并正在考虑多个线程的可能性)并且必须在每一帧对每个对象执行一些操作,上面的事情很容易实现吗?看看 IEnumerable ,它似乎只跟踪当前位置,所以我不确定是否可以使用普通的通用集合将枚举分解为“块”。
很抱歉这个问题。我在上面使用了项目符号而不是伪代码,因为我什至不知道如何随心所欲地编写伪代码。我的.NET知识纯粹是简单的业务知识,而且我对委托和线程等还很陌生。我主要想知道上述方法是否适合追求,以及委托/lambdas是否不必担心什么时候涉及到它们的并行化。
I recently asked about functional programs having no side effects, and learned what this means for making parallelized tasks trivial. Specifically, that "pure" functions make this trivial as they have no side effects.
I've also recently been looking into LINQ and lambda expressions as I've run across examples many times here on StackOverflow involving enumeration. That got me to wondering if parallelizing an enumeration or loop can be "easier" in C# now.
Are lambda expressions "pure" enough to pull off trivial parallelizing? Maybe it depends on what you're doing with the expression, but can they be pure enough? Would something like this be theoretically possible/trivial in C#?:
- Break the loop into chunks
- Run a thread to loop through each chunk
- Run a function that does something with the value from the
current loop position of each thread
For instance, say I had a bunch of objects in a game loop (as I am developing a game and was thinking about the possibility of multiple threads) and had to do something with each of them every frame, would the above be trivial to pull off? Looking at IEnumerable it seems it only keeps track of the current position, so I'm not sure I could use the normal generic collections to break the enumeration into "chunks".
Sorry about this question. I used bullets above instead of pseudo-code because I don't even know enough to write pseudo-code off the top of my head. My .NET knowledge has been purely simple business stuff and I'm new to delegates and threads, etc. I mainly want to know if the above approach is good for pursuing, and if delegates/lambdas don't have to be worried about when it comes to their parallelization.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
首先,请注意,为了“纯粹”,方法不仅必须没有副作用。当给定相同的参数时,它还必须始终返回相同的结果。因此,例如“Math.Sin”方法是纯方法。你输入 12,它就会返回给你 sin(12),而且每次都是一样的。即使 GetCurrentTime() 方法没有副作用,它也不是纯粹的;每次调用它时,无论传入什么参数,它都会返回不同的值。
另请注意,纯方法实际上不应该抛出异常;出于我们的目的,异常被视为可观察到的副作用。
其次,是的,如果您可以推断方法的纯度,那么您可以做一些有趣的事情来自动并行化它。问题是,几乎没有方法实际上是纯粹的。此外,假设你确实有一个纯粹的方法;由于纯方法是记忆化的完美候选者,并且由于记忆化引入了副作用(它会改变缓存!),因此采用应该是纯方法的方法然后使它们变得不纯是非常有吸引力的。
正如乔·达菲所说,我们真正需要的是某种“抑制副作用”的方法。某种方法可以在方法周围画一个框,并说“这个方法不是没有副作用的,但它的副作用在这个框之外是不可见的”,然后使用这个事实来驱动安全自动并行化。
我很想找到一些方法将这些概念添加到 C# 等语言中,但这完全是蓝天开放研究问题的内容;没有任何有意或暗示的承诺。
First off, note that in order to be "pure" a method must not only have no side effects. It must also always return the same result when given the same arguments. So, for example, the "Math.Sin" method is pure. You feed in 12, it gives you back sin(12) and it is the same every time. A method GetCurrentTime() is not pure even if it has no side effects; it returns a different value every time you call it, no matter what arguments you pass in.
Also note that a pure method really ought not to ever throw an exception; exceptions count as observable side effects for our purposes.
Second, yes, if you can reason about the purity of a method then you can do interesting things to automatically parallelize it. The trouble is, almost no methods are actually pure. Furthermore, suppose you do have a pure method; since a pure method is a perfect candidate for memoization, and since memoization introduces a side effect (it mutates a cache!) it is very attractive to take what ought to be pure methods and then make them impure.
What we really need is some way to "tame side effects" as Joe Duffy says. Some way to draw a box around a method and say "this method isn't side-effect-free, but its side effects are not visible outside of this box", and then use that fact to drive safe automatic parallelization.
I'd love to figure out some way to add these concepts to languages like C#, but this is all totally blue-sky open-research-problem stuff here; no promises intended or implied.
Lambda 的应该是纯的。然后,FrameWork 通过向 LINQ 查询 (PLINQ) 添加简单的
.AsParallel
来提供自动并行化。但这不是自动的或有保证的,程序员有责任使/保持它们纯净。
Lambda's should be pure. And then the FrameWork offers automatic paralellization with a simple
.AsParallel
addition to a LINQ query (PLINQ).But it is not automatic or guaranteed, the programmer is responsible to make/keep them pure.
lambda 是否是纯的取决于它正在做什么。作为一个概念,它既不是纯粹的,也不是不纯粹的。
例如:以下 lambda 表达式是不纯的,因为它正在读取和写入主体中的单个变量。并行运行会产生竞争条件。
相反,下面的委托是纯粹的并且没有竞争条件。
Whether or not a lambda is pure is tied to what it is doing. As a concept it is neither pure or impure.
For example: The following lambda expression is impure as it is reading and writing a single variable in the body. Running it in parallel creates a race condition.
Contrarily the following delegate is pure and has no race conditions.
至于循环部分,您还可以使用
Parallel.For
和Parallel.ForEach
作为有关游戏中对象的示例。这也是 .net 4 的一部分,但您可以下载它。As for the loop part, you could also use the
Parallel.For
andParallel.ForEach
for the example about the objects in a game. This is also part of .net 4 , but you can get it as a download.