代码之家  ›  专栏  ›  技术社区  ›  Lars Westergren

高度可变域中的不可变功能对象

  •  25
  • Lars Westergren  · 技术社区  · 18 年前

    我目前正在利用业余时间学习Scala的函数式编程,我有一个空闲的新手问题。

    我可以看到,在进行诸如计算Haar小波变换之类的工作时,拥有不可变对象的优雅之处,即当对象所表示的数据本身不变时。

    但我看到一个博客,其中有人以一个小游戏为例演示了不变性。若一个生物对象受到伤害,它并没有改变它的状态——它返回一个新的生物对象,并带有新的生命值和新的“向X攻击”标志。但是魔兽世界说,如果我们要设计类似MMORPG的东西。战场上有一百名球员。。。可能会有数千次攻击和加减速/减减速法术效果以不同的方式影响他们。仍然可以用完全不变的对象设计系统吗?在我看来,每一个“滴答声”都会出现大量新实例。要获得当前有效的对象实例,所有客户端都必须不断地通过某种中心“游戏世界”对象,或者?

    函数式编程是否为此而扩展,或者这是“最佳工作的最佳工具,在这里可能不是不变的”?

    8 回复  |  直到 7 年前
        1
  •  16
  •   cjs    9 年前

    在我看来,每一个“滴答声”都会出现大量新实例。

    事实上,情况就是这样。我有一个Haskell应用程序,它可以读取市场数据提要(在六小时的交易日内,我们感兴趣的数据大约有500万条消息),并维护各种信息的“当前状态”,例如最新的买卖价格和工具数量,我们的模型是否适合市场,等等。在分析模式下,对记录的提要模拟这个程序的运行,看着它在运行的前500秒内分配和GC接近288 TB的内存(或接近我机器RAM大小的50000倍),这是相当可怕的。(如果不进行评测,这个数字会高得多,因为评测不仅会降低应用程序的速度,而且还会迫使它在一个内核上运行。)

    但是请记住,纯语言实现中的垃圾收集器针对这种行为进行了优化。我对我的应用程序的总体速度非常满意,而且我认为这是一个相当高的要求,因为我们必须每秒解析来自市场提要的数百条消息,进行一些相当广泛的计算来构建我们的模型,并使用该模型生成订单,以便尽快进入交易所。

        2
  •  6
  •   Dickon Reed    18 年前

    通常在函数编程中,您将不具有C++风格的构造函数。因此,即使从概念上讲您一直在创建对象,但这并不意味着编译器必须编写代码来分配新对象,因为它不会影响程序的行为。由于数据是不可变的,编译器可以看到您刚才指定的值以及传递到函数中的值。

    可以 创建非常紧凑的编译代码,在需要时只计算特定对象中的字段。这项工作的好坏取决于您使用的编译器的质量。然而,干净的函数式编程代码告诉编译器的关于代码的信息比类似程序的C编译器所能承担的要多得多,因此是一个好的编译器 生成比预期更好的代码。

        3
  •  4
  •   Jonathan Tran    18 年前

    不变性的一个例子。由于游戏分布在服务器和玩家的系统中,因此绝对没有一个中心的“游戏世界”对象。因此,任何通过网络发送的对象都是不可变的,因为它不会被接收者改变。相反,一个新的对象或消息将作为响应发送(如果有)。

    我从来没有写过分布式游戏,所以我不知道它们是如何实现的,但我怀疑对对象的更新要么是本地计算的,要么是作为差异通过网络发送的。

    这个游戏非常简单,所以我怀疑只要有可能,很多都是在本地计算的。假设两个玩家的电脑在游戏状态方面最初是同步的。然后你的对手点击移动他的轻型坦克进入你的基地。一条消息(不可变)通过电线发送给您。由于移动坦克的算法(可能)是确定性的,因此您的命令&征服可以在你的屏幕上移动对手的坦克,更新你的游戏状态(可以是不变的或可变的)。当轻型坦克进入你的猛犸坦克射程时,你的坦克开火。服务器上会生成一个随机值(在这种情况下,任意选择一台计算机作为服务器),以确定射击是否击中对手。假设坦克被击中并且必须更新你对手的坦克,只有差异——坦克的新装甲等级降低到22%——通过电线发送,以同步两名玩家的游戏。此消息是不可变的。

        4
  •  3
  •   Charles Duffy    18 年前

    关于不变性需要注意的一点是(如果实现正确),它使对象创建相对轻量级。如果字段是不可变的,则可以在实例之间共享。

        5
  •  3
  •   Rick Minerich    18 年前

    在设计一个功能程序时,要考虑到,像你的状态一样,不可变的对象会有一些开销。记住,MMORPG程序中的对象是不可变的,这一点也很重要,因为它本身就具有更高的可伸缩性。因此,设备的初始投资可能会更高,但随着事情的发展,你将能够扩展到你的玩家基础。

    另一个重要的问题是,现在最漂亮的机器每CPU有6个内核。考虑一个具有6个内核的双CPU机器。这12个核心中的一个可以进行垃圾收集,因此应用程序可以轻松地扩展到其他11个核心,从而可以抵消分解大量对象的开销。

        6
  •  3
  •   ironfroggy    18 年前

        7
  •  2
  •   Lars Westergren    16 年前

    我今天发现了一个博客,它正好处理了我在这篇文章中提出的问题:

    http://prog21.dadgum.com/23.html

        8
  •  0
  •   Rik elirevach    18 年前

    就像几乎所有编程工具一样,不可变对象功能强大,但在错误的情况下是危险的。我认为这个游戏的例子不是很好,或者至少不是很做作。

    埃里克·利珀特有一些有趣的故事 posts 关于不变性的话题,这是一本很有趣的书。