代码之家  ›  专栏  ›  技术社区  ›  Bob

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

  •  5
  • Bob  · 技术社区  · 14 年前

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

    我最近还研究了linq和lambda表达式,因为我在这里多次遇到过涉及枚举的stackoverflow示例。这让我想知道在C中,并行化一个枚举或循环是否更容易。

    lambda表达式是否“纯粹”到足以实现琐碎的并行化?也许这取决于你在表达什么,但是它们是否足够纯净?在C中,这样的东西在理论上是可能的还是微不足道的?:

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

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

    对这个问题感到抱歉。我用上面的子弹代替了伪代码,因为我甚至都不知道怎么把伪代码写下来。我的.NET知识纯粹是简单的业务内容,我对委托和线程等不熟悉。我主要想知道上面的方法是否适合追求,以及委托/lambda在并行化方面是否不必担心。

    5 回复  |  直到 14 年前
        1
  •  17
  •   Eric Lippert    14 年前

    首先,要注意的是,为了“纯”一个方法必须不仅没有副作用。在给定相同参数时,它也必须始终返回相同的结果。例如,“math.sin”方法是纯的。你吃了12个,它会把罪还给你,每次都是一样的。getcurrentTime()方法不是纯的,即使它没有副作用;每次调用它时,它都会返回不同的值,不管传入的参数是什么。

    还要注意,纯方法确实不应该抛出异常;对于我们的目的来说,异常被视为可观察的副作用。

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

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

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

        2
  •  13
  •   Henk Holterman    14 年前

    lambda的 应该 保持纯洁。然后框架提供了一个简单的 .AsParallel 添加到LINQ查询(PLINQ)中。

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

        3
  •  3
  •   JaredPar    14 年前

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

    例如:下面的lambda表达式在读取和写入主体中的单个变量时是不纯的。并行运行会创建一个竞争条件。

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

    相反,下面的代表是纯粹的,没有种族条件。

    Func<bool> del = () => true;
    
        4
  •  3
  •   Francisco Noriega    14 年前

    对于循环部分,也可以使用 Parallel.For Parallel.ForEach 例如关于游戏中对象的例子。这也是.NET 4的一部分,但您可以下载它。

        5
  •  2
  •   Fadrian Sudaman    14 年前

    有13个部分在阅读中讨论.NET 4.0中新的并行性支持 here . 它包括关于LINQ和PLINQ的讨论,以及第7部分。这是一本很好的书,看看吧