方法是否使用类实例化,消耗大量内存(在 Scala 中)?

Mak*_*e42 5 python oop jvm scala

情况

我将构建一个密集数据操作的程序(使用 Scala 或 Python - 尚未决定)。我看到两种市长的做法:

  1. 方法:定义数据的集合。写我的函数。通过函数发送整个数据集。
  2. 方法:定义一个表示单个数据实体的数据类,并将方法(类成员)编码到数据类中。应该灵活的部分方法通过 Scala 函数或 Python lambda 发送到方法。

副题

我不确定,但第一种方法可能更像函数式编程,第二种方法更像 OOP,对吗?顺便说一句,我喜欢函数式编程和 OOP(有人说它们是对立的,但 Odersky 尽力用 Scala 来反驳这一点)。

主要问题

我更喜欢第二种方法,因为

  1. 对我来说似乎更简洁。
  2. 它使在无共享架构大数据设置中分发程序变得更容易,因为它遵循数据本地性原则为数据带来功能,而不是将数据引入功能。

但是,我担心如果我有很多数据(我确实有),我会消耗很多内存,因为该方法可能必须被实例化很多次。

  1. 问题: Scala/JVM 是这样吗?如果不是,如何解决?
  2. 问题:这对 Python 是真的吗——如果不是,它是如何解决的?

后续问题

引导我:我应该选择哪种方法?

更多上下文

  • 我有很多数据(数百万,可能是数十亿的数据对象)
  • 我没有那么多功能要实现。为了给出一个大概的数字,让我们说大约 10。
  • 不过,我希望对这些方法有很多调用。
  • 假设每个数据实体有 100 次调用,那么整个程序将有 100 * 100 万次调用。
  • 我的数据类代表单个实体,而不是整个数据集。
  • 我担心的是,每次实例化我的 DataObject 类时,都需要复制该方法的代码,这会消耗大量内存和处理能力。我不知道 JVM 和 Python 的内部在这方面是如何工作的,以及这是否属实——这就是我要问的。

这是一个粗略的 DataObject 类:

class DataObject {

    List datavalues

    def mymethod(){
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

Mis*_*agi 2

哪种方法最好完全取决于您的问题。如果操作很少,功能就更简单。如果您有许多依赖于数据类型/特征的操作,那么类是有效的。

就我个人而言,我更喜欢为相同类型的数据提供类,以提高抽象性和模块化性。基本上,使用类需要您考虑您的数据是什么样的、数据上允许什么以及什么是合适的。它强制你分开、划分并理解你在做什么。完成此操作后,您可以将它们视为可以正常工作的黑匣子。

我见过许多数据分析程序失败,因为它们只有处理任意数据的函数。起初,这只是简单的计算。然后需要保留/缓存状态,因此直接附加或修改数据。然后有人意识到,如果你之前做了 x,那么以后就不应该做 y,所以各种标志、字段和其他东西都会被附加,只有函数 a、b 和 d 能够理解。然后有人添加了函数 f 对其进行了扩展,而有人添加了函数 k 对其进行了不同的扩展。这会创建一个无法理解、维护或信任创建结果的 cluster-foo。

因此,如果您不确定,请参加课程。最后你会更幸福。


关于你的第二个问题,我只能回答python。然而,许多语言都有类似的做法。

python 中的常规方法是在类上定义并用它创建的。这意味着方法所代表的实际函数由所有实例共享,没有内存开销。基本上,裸实例只是对类的包装引用,从中获取方法。只有实例独有的内容(例如数据)才会显着增加内存。

调用方法确实会增加一些开销,因为该方法会绑定到实例 - 基本上,该函数是从类中获取的,并且第一个参数self会被绑定。这在技术上会产生一些开销。

# Method Call
$ python -m timeit -s 'class Foo():' -s ' def p(self):' -s '  pass' -s 'foo = Foo()' 'foo.p()'
10000000 loops, best of 3: 0.158 usec per loop
# Method Call of cached method
$ python -m timeit -s 'class Foo():' -s ' def p(self):' -s '  pass' -s 'foo = Foo()' -s 'p=foo.p' 'p()'
10000000 loops, best of 3: 0.0984 usec per loop
# Function Call
$ python -m timeit -s 'def p():' -s ' pass' 'p()'
10000000 loops, best of 3: 0.0846 usec per loop
Run Code Online (Sandbox Code Playgroud)

然而,实际上任何操作都会这样做;如果您的应用程序除了调用您的方法之外什么都不做,并且该方法也不执行任何操作,您只会注意到增加的开销。

我还看到人们编写具有如此多抽象级别的数据分析应用程序,实际上他们大多只是调用方法/函数。这是一般编写代码的味道,而不是是否使用方法函数。

因此,如果您不确定,请参加课程。最后你会更幸福。