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 框架:当请求超出可用线程时会发生什么 的相关文章

  • 如何延迟 onClick 操作

    我正在尝试在 java 应用程序 android 中做一些事情 并且我需要一些东西来延迟 等待循环的秒数 我怎样才能延迟android功能 我尝试过使用 Thread sleep TimeUnit sleep 但它只会执行几秒钟的不负责任的
  • 并发访问且不受数据结构的影响

    问题是这样的 我有一个包含 500 个指针的数组 它们指向双向链表中的 500 个元素 有 10 个并行运行的线程 每个线程运行 50 个循环 并尝试释放列表中的某些元素 该列表已排序 包含简单整数 并且有 10 个其他线程并行运行 搜索包
  • 如何处理或避免BlockedIndefinitelyOnSTM异常?

    我花了很多时间来解决我正在处理的应用程序中遇到的问题 该应用程序是一个 Web 应用程序 使用 scotty 公开 REST 端点 它使用一个TVar保持其更新的状态STM a由前端层触发的动作 由于该应用程序基于事件溯源原则 因此业务层生
  • 为并行的小型已知冻结进程创建匿名 AsyncTask 是一个好习惯吗? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 例如 您要做一些需要几秒钟的事情 并且不想冻结您的 UI 线程 对吗 您可以使用 AsyncTask 但您不想创建外部 或内部 类来解决小冻结问
  • 如何使用单独的线程部分重绘自定义 SurfaceView 而不会丢失以前的编辑?

    我目前在按照自定义绘图时遇到问题SurfaceView来自不在我的主 UI 上的线程 这SurfaceView占据整个屏幕 Galaxy S3 全屏 并且必须从多个来源进行更新 问题是习惯SurfaceView不会保存 UI 更新之间的更改
  • 您可以为 None 指定类型参数或告诉编译器它是一个 Option[String] 吗?

    我想知道我是否可以在我的代码中写这样的东西 None String 我很惊讶没有人提到它的存在Option empty scala gt Option empty String res0 Option String None 请注意 在许多
  • ASP.NET MVC 多线程

    我想在我的 asp net mvc 应用程序中实现这样的逻辑 user clicks a button gt server executes some time consuming logic in 15 threads i get dat
  • 以线程安全的方式获取随机数

    这是一篇描述随机数线程安全性的好文章 以线程安全的方式获取随机数 http blogs msdn com b pfxteam archive 2009 02 19 9434171 aspx 但我坚持使用 RandomGen2 示例 publ
  • 无法访问类型的封闭实例。 [复制]

    这个问题在这里已经有答案了 整个代码是 public class ThreadLocalTest ThreadLocal
  • Java-线程与CPU的关系

    我对多线程还很陌生 我正在开发一个项目 尝试在我的 Java 程序中使用 4 个 CPU 我想做类似的事情 int numProcessors Runtime getRuntime availableProcessors ExecutorS
  • 线程安全的 C++ 堆栈

    我是 C 新手 正在编写一个多线程应用程序 不同的编写者将对象推入堆栈 读者将它们从堆栈中拉出 或至少将指针推入对象 C 中是否有任何内置结构可以在不添加锁定代码等的情况下处理此问题 如果没有 那么 Boost 库呢 EDIT 你好 感谢您
  • Spark 数据帧:根据另一列的值提取一列

    我有一个包含带有连接价目表的交易的数据框 paid currency EUR USD GBP 49 5 EUR 99 79 69 客户已支付 49 5 欧元 如 货币 列中所示 我现在想将支付的价格与价目表中的价格进行比较 因此 我需要根据
  • 排序线程按照它们创建/启动的顺序运行

    我如何按照线程实例化的顺序对线程进行排序 我怎样才能让下面的程序按顺序打印数字1 10 public class ThreadOrdering public static void main String args class MyRunn
  • Linux/POSIX:为什么 fork() 不分叉*所有*线程

    众所周知 POSIX下创建新进程的默认方式是使用fork 在 Linux 下 这在内部映射到clone 我想知道的是 众所周知 当一个人打电话时fork 子进程是用单个线程创建的 调用的线程fork cf https linux die n
  • Scala sbt 项目给出 NullPointerException?

    当我运行命令时sbt clean compile run在我的 sbt 项目中 它给出了空指针异常 这是控制台输出 info Loading project definition from home dnilesh workspace wi
  • 配置Scala工作表的工作目录

    我希望 Scala 工作表 和 Scala 解释器 的工作目录是 Eclipse 项目路径而不是 Eclipse 安装目录 我怎样才能 非编程方式 实现这一目标 我知道我可以使用System setProperty user dir 但恕我
  • 将字符串转换为枚举值的 Scala 安全方法

    假设我有枚举 object WeekDay extends Enumeration type WeekDay Value val Mon Tue Wed Thu Fri Sat Sun Value 我希望能够将 String 转换为 Wee
  • 如何在Slick 3.0.0中使用StaticQuery?

    在 Slick 2 1 中 我使用以下代码从文件执行 sql 查询 def fetchResult T sql String implicit getResult GetResult T List T val query Q queryNA
  • 在案例类中重载 unapply 方法:scala

    考虑下面的代码 case class User id Int name String object User def unapply str String Some User 0 str Scala 抱怨 错误 无法解析重载未应用 案例类
  • Spark Scala 相当于 SKEW 连接提示

    Spark SQL 有一个可用的倾斜提示 请参阅here https docs databricks com spark latest spark sql skew join html relation columns and skew v

随机推荐