【问题标题】:Do I generate a side effect?我会产生副作用吗?
【发布时间】:2017-12-04 07:21:53
【问题描述】:

我有以下功能,想知道是否会产生副作用:

  def build[F[_] : Monad : Foldable, A]
  (consumer: Consumer[String, String])(cb: Vector[KkConsumerRecord] => F[A])
  : KkConsumerThread = {
    val thread = delegate.newThread(() => {
      pool(consumer)(cb)
    })
    thread.setDaemon(true)
    KkConsumerThread(thread)
  } 

在函数内部,我创建了一个线程,但还没有启动它。这对我来说意味着,我还没有产生任何副作用。我说的对吗?

【问题讨论】:

    标签: scala functional-programming


    【解决方案1】:

    基本上,您似乎正在产生副作用。这样想 - 如果你反复调用这个函数,你最终会耗尽内存(通过达到 OS 线程 # 限制或 java 堆大小限制)。

    【讨论】:

    • 是的,我产生了副作用但我还没有启动线程,这是否意味着已经有副作用?我可以生成多少个线程,而不是内存不足?
    • 是的,它算作副作用。我可以问你问题的目的吗?关于线程# - 通常,基于 *nix 的系统需要几千个。你可以在你的电脑上运行它,看看你什么时候内存不足。此外,在 java 上,每个线程使用 512kb 堆栈,因此如果您有 100mb 最大内存,最多 200 个线程会由于堆空间而导致内存不足错误。
    • 目的是,我想在单独的线程上启动 kafka 消费者来监听传入的消息。这就是为什么,它需要自己的线程。
    • 听起来应该发生在其他地方。我不确定你的这部分代码应该做什么,但如果它意味着没有副作用,我不建议在这里创建一个线程。
    【解决方案2】:

    你在这里产生了几个副作用:

    • 从或多或少透明的thread.setDaemon(true) 开始,假设您只执行一次(在您返回KkConsumerThread 之前似乎没有人阅读false

    • delegate.newThread( 在 JVM 中注册新线程(假设它创建了一个 JVM 线程):http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Thread.java#393,因此它可能在 JConsole/JVisualVM/jstack 中被视为未启动线程:

      g.addUnstarted(); //adding thread to default THread group
      ... //a lot of other global mutable stuff
      

    请参阅:http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Thread.java#327

    因此,您应该注意线程生命周期(如果您过于频繁地调用它),尤其是在您执行一些其他低级操作时。

    附:据我所知,新线程的创建也会立即(在开始之前)分配一个调用堆栈。

    【讨论】:

    • 那么当我产生副作用时,它算作副作用吗?即使我稍后启动线程。
    • @zero_coding 是的,所有线程都保存在具有全局范围的“注册表”中,您只需更改该注册表。它不像在正常情况下创建 Futures 那样具有破坏性,但如果你打算经常调用你的“函数”可能会变得更糟
    • @zero_coding 我不记得了,但我认为每次创建线程时它都会分配堆栈
    猜你喜欢
    • 2016-12-11
    • 1970-01-01
    • 2016-06-23
    • 2012-05-29
    • 1970-01-01
    • 2020-09-09
    • 1970-01-01
    • 2012-09-19
    • 1970-01-01
    相关资源
    最近更新 更多