Play 框架:当请求超出可用线程时会发生什么

2024-04-29

我的线程池中有一个线程服务阻塞请求。

  def sync = Action {
    import Contexts.blockingPool
    Future { 
        Thread.sleep(100)
    } 
    Ok("Done")
  }

在 Contexts.blockingPool 中配置为:

custom-pool {
    fork-join-executor {
            parallelism-min = 1
            parallelism-max = 1
    }
}

理论上,如果上述请求同时收到 100 个请求,则预期行为应该是:1 个请求应休眠(100),其余 99 个请求应被拒绝(或排队直至超时?)。然而,我观察到创建了额外的工作线程来服务其余的请求。我还观察到,随着池中线程数量小于收到的请求,延迟会增加(服务请求变慢)。

如果收到的请求大于配置的线程池大小,预期的行为是什么?


您的测试结构不正确,无法检验您的假设。 如果你过去文档中的这一部分 http://www.playframework.com/documentation/2.3.1/ThreadPools你会看到 Play 有一些线程池/执行上下文。对于你的问题来说,最重要的是默认线程池以及它与您的操作所服务的 HTTP 请求有何关系。

正如文档所描述的,默认线程池是所有应用程序代码默认运行的地方。 IE。所有操作代码,包括所有Future的(没有显式定义自己的执行上下文),将在此执行上下文/线程池中运行。所以用你的例子:

def sync = Action {

  // *** import Contexts.blockingPool
  // *** Future { 
  // *** Thread.sleep(100)
  // ***} 

  Ok("Done")
}

您操作中的所有代码not评论者// ***将运行在默认线程池。 IE。当请求被路由到您的操作时:

  1. the FutureThread.sleep将被分派到您的自定义执行上下文
  2. 然后无需等待Future完成(因为它在自己的线程池中运行[Context.blockingPool] 因此不会阻塞默认线程池上的任何线程)
  3. your Ok("Done")语句被评估并且客户端收到响应
  4. 大约。收到响应后 100 毫秒,您的Future完成

因此,为了解释您的观察结果,当您同时发送 100 个请求时,Play 将很乐意接受这些请求,路由到您的控制器操作(在默认线程池),发送到您的Future然后回复客户。

默认池的默认大小为

play {
  akka {
    ...
    actor {
      default-dispatcher = {
        fork-join-executor {
          parallelism-factor = 1.0
          parallelism-max = 24
        }
      }
    }
  }
}

每个核心使用 1 个线程,最多 24 个。 鉴于你的行动几乎没有什么作用(不包括Future),您将能够毫不费力地处理每秒 1000 个请求。你的Future然而,将需要更长的时间来处理积压,因为您正在阻塞自定义池中的唯一线程(blockingPool).

如果您使用我稍微调整过的操作版本,您将在日志输出中看到证实上述解释的内容:

object Threading {

  def sync = Action {
    val defaultThreadPool = Thread.currentThread().getName;

    import Contexts.blockingPool
    Future {
      val blockingPool = Thread.currentThread().getName;
      Logger.debug(s"""\t>>> Done on thread: $blockingPool""")
      Thread.sleep(100)
    }

    Logger.debug(s"""Done on thread: $defaultThreadPool""")
    Results.Ok
  }
}

object Contexts {
  implicit val blockingPool: ExecutionContext = Akka.system.dispatchers.lookup("blocking-pool-context")
}

您的所有请求都会首先得到迅速处理,然后您的Future之后就一一完成了。

总而言之,如果您确实想测试 Play 如何在只有一个线程处理请求的情况下处理许多并发请求,那么您可以使用以下配置:

play {
  akka {
    akka.loggers = ["akka.event.Logging$DefaultLogger", "akka.event.slf4j.Slf4jLogger"]
    loglevel = WARNING
    actor {
      default-dispatcher = {
        fork-join-executor {
          parallelism-min = 1
          parallelism-max = 1
        }
      }
    }
  }
}

您可能还想添加Thread.sleep像这样的操作(以减慢默认线程池的孤独线程速度)

    ...
    Thread.sleep(100)
    Logger.debug(s"""<<< Done on thread: $defaultThreadPool""")
    Results.Ok
}

现在您将有 1 个用于请求的线程和 1 个用于您的Future的。 如果您以高并发连接运行此程序,您会注意到客户端会在 Play 逐一处理请求时阻塞。这就是你期望看到的......

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Play 框架:当请求超出可用线程时会发生什么 的相关文章

  • Scala 2.9 无法在 Windows XP 上运行“hello world”示例

    我正在尝试在 Windows XP 上使用 scala 2 9 1 Final 运行 HelloWorld 示例 object HelloWorld extends App println Hello World 文件另存为Hello sc
  • 如何在.NET 中编写安全/正确的多线程代码?

    今天我必须修复一些使用线程的旧 VB NET 1 0 代码 问题在于从工作线程而不是 UI 线程更新 UI 元素 我花了一些时间才发现可以使用 InvokeRequired 断言来查找问题 除了上面提到的并发修改问题之外 还可能遇到死锁 竞
  • std::map 只读操作的线程安全

    我有一个 std map 用于将值 字段 ID 映射到人类可读的字符串 当我的程序在任何其他线程启动之前启动时 该映射会被初始化一次 之后就不会再被修改 现在 我为每个线程提供了这个 相当大的 映射的自己的副本 但这显然是内存使用效率低下
  • 从 HList 获取元素

    我尝试了 HList 并按预期进行了以下工作 val hl 1 foo HNil val i Int hl 0 val s String hl 1 但是 我无法让以下代码正常工作 让我们暂时假设对列表进行随机访问是一个聪明的主意 class
  • c++11 中的 std::thread 问题

    我在尝试从标准模板库编译具有多线程的程序时遇到一些麻烦 当我尝试编译以下程序时 它返回一个晦涩的错误 include
  • 规范化且不可变的数据模型

    Haskell如何解决 规范化不可变数据结构 问题 例如 让我们考虑一个表示前女友 男友的数据结构 data Man Man name String exes Woman data Woman Woman name String exes
  • 如果未返回,则在一段时间后终止线程

    我有一个线程从网络或串行端口获取一些数据 如果 5 秒内没有收到数据 则线程必须终止 或返回 false 换句话说 如果线程运行时间超过 5 秒 则必须停止 我用 C 编写 但任何 NET 语言都可以 有两种方法 1 封装超时 从网络或串行
  • CPU Relax 指令和 C++11 原语

    我注意到许多使用特定于操作系统的原语实现的无锁算法 例如所描述的自旋锁here http locklessinc com articles locks 使用 Linux 特定的原子原语 经常使用 cpurelax 指令 使用 GCC 可以通
  • Play框架:单属性案例类的JSON读取

    我正在尝试为包含单个属性的案例类创建隐式 JSON Reads 但收到错误 Reads Nothing 不符合预期类型 这是代码 import play api libs functional syntax import play api
  • 在不支持 CAS 操作的处理器上进行 CompareAndSet

    今天 我在一次采访中被问到下一个问题 如果您在具有不支持 CAS 操作的处理器的机器上调用 AtomicLong 的compareAndSet 方法 会发生什么情况 您能否帮我解决这个问题 并在可能的情况下提供一些全面描述的链接 From
  • Scala中有类似Java Stream的“peek”操作吗?

    在Java中你可以调用peek x gt println x 在 Stream 上 它将对每个元素执行操作并返回原始流 这与 foreach 不同 foreach 是 Unit Scala 中是否有类似的东西 最好是适用于所有 Monady
  • Slick和bonecp:org.postgresql.util.PSQLException:FATAL:抱歉,太多客户端已经错误

    当我在本地开发应用程序时 我使用以下命令启动我的 play2 应用程序sbt run 我喜欢如何更改代码 然后重新加载浏览器以查看我的更改 在大约 10 次代码更改之后 我收到 postgresql 太多连接错误 见下文 我的数据库连接使用
  • Java 8 Stream,获取头部和尾部

    Java 8 引入了Stream http download java net jdk8 docs api java util stream Stream html类似于 Scala 的类Stream http www scala lang
  • 如何通过start-stop-daemon正常关闭Spring Boot应用程序[重复]

    这个问题在这里已经有答案了 我们有一个多线程 Spring Boot 应用程序 它作为守护进程在 Linux 机器上运行 当我尝试像这样通过启动停止守护进程停止应用程序时 start stop daemon stop quiet retry
  • 理解 JavaScript 的单线程本质

    我一直在阅读 John Resig 的 JavaScript Ninja 的秘密 它解释了 JavaScript 是单线程的 但是 我尝试对此进行测试 但我不确定要从这里删除什么 executing this in browser func
  • 通过推送通知唤醒

    Suppose 有一些对象 例如 一个数组a 和依赖于对象的条件 例如 a empty 当前线程以外的某些线程可以操作该对象 a 因此条件评估值的真实性会随着时间的推移而变化 如何让当前线程在代码中的某个时刻休眠 并在条件满足时通过推送通知
  • IntelliJ:线程“主”java.lang.NoClassDefFoundError中的异常:org/apache/spark/sql/types/DataType

    附言 有一个类似的问题here https stackoverflow com questions 40287289 java lang noclassdeffounderror org apache spark logging 但那是在
  • 如何限制Erlang VM(BEAM)使用的核心数量?

    我正在具有 2 个四核 Xeon E5520 2 2GHz 24 0GB RAM 和 Erlang R15B02 启用 SMP 的节点上运行实验 我想知道是否可以限制Erlang VM使用的核心数量 以便我可以暂时禁用一些核心并逐步增加数量
  • 如何在 scala repl 和 sbt 控制台中关闭/打开 typer 阶段

    是否可以在不退出当前会话的情况下切换阶段 我尝试进入 power 模式 但它仍然不打印类型 在SBT中只需添加以下设置 set scalacOptions in Compile console Xprint typer 在 REPL 中你可
  • fprintf() 线程安全吗?

    我正在为野人就餐问题的某些变量编写一个 C 解决方案 现在 我创建线程 每个线程都将 FILE 获取到同一个调试文件 在线程内我正在使用 fprintf 进行一些打印 打印的语句不受任何类型的互斥锁等保护 我没有在调试文件中观察到任何交错行

随机推荐