12

考虑最简单的 scotty 应用程序:

{-# LANGUAGE OverloadedStrings #-}
import Web.Scotty

import Data.Monoid (mconcat)

main = scotty 3000 $ do
    get "/:word" $ do
        beam <- param "word"
        html $ mconcat ["<h1>Scotty, ", beam, " me up!</h1>"]

我将这段代码放入app.hs并用 GHC 编译。我用./app. 简单的。

  1. 当人们访问该网站时,究竟会发生什么?只有一个./app在运行。每当每个用户触发一行时,是否会在同一个应用程序中创建一个新线程get "/:word" $ do?可以存在多少这样的线程?千?万?

  2. 运行./app后显示消息Setting phasers to stun... (port 3000) (ctrl-c to quit)。但它没有显示更多。它不输出传入的网络请求。我怎样才能让它做到这一点?这对于记录目的很有用。

4

2 回答 2

14

假设您使用 GHC,对 scotty 服务器的每个请求本质上都会创建一个由 GHC 运行时调度的“绿色线程”。您可以轻松地同时运行数千个。

Scotty 本身不做任何请求日志记录,但由于它构建在WAI之上,因此您可以使用为其存在的任何中间件组件,例如RequestLogger.

{-# LANGUAGE OverloadedStrings #-}
import Web.Scotty
import Network.Wai.Middleware.RequestLogger

import Data.Monoid (mconcat)

main = scotty 3000 $ do
    middleware logStdoutDev

    get "/:word" $ do
        beam <- param "word"
        html $ mconcat ["<h1>Scotty, ", beam, " me up!</h1>"]
于 2014-08-27T17:23:15.783 回答
11

1. 当人们访问该网站时,真正发生了什么?只有一个 ./app 正在运行。每当每个用户触发 get "/:word" $ do 行时,是否会在同一个应用程序中创建一个新线程?可以存在多少这样的线程?千?万?

Scotty 是围绕warp构建的,但可以使用任何其他实现Web 应用程序接口 (WAI)的库。forkIOUnmasked使用(隐藏在fork模块中)创建了一个新的轻量级线程Network.Wai.Handler.Warp.Run。您可以拥有其中的许多

并发是“轻量级的”,这意味着线程创建和上下文切换开销都极低。Haskell 线程的调度是在 Haskell 运行时系统内部完成的,不使用任何操作系统提供的线程包。(来源)

这是nginx 和 warp 之间的性能比较,其中还包括有关 warp 背后的一般思想的信息。

2. 运行 ./app 后会显示消息 Setting Phasers to stun... (port 3000) (ctrl-c to quit)。但它没有显示更多。它不输出传入的网络请求。我怎样才能让它做到这一点?这对于记录目的很有用。

你的do块是什么类型的?应该是ScottyM,因为scotty :: Port -> ScottyM () -> IO ()。IfScottyM是 的一个实例MonadIO,您可以liftIOputStrLn(或任何其他IO操作)一起使用。

现在,ScottyM实际上是 的类型同义词ScottyT,实际上是 的实例MonadIO。此外,inner monadActionM也是 的类型同义词ActionT,它也是MonadIO. 因此,日志记录就像

main = scotty 3000 $ do
    liftIO $ putStrLn "incoming request"
    get "/:word" $ do
        beam <- param "word"
        liftIO $ print $ mconcat ["get, word = ", beam]
        html $ mconcat ["<h1>Scotty, ", beam, " me up!</h1>"]

但是,请记住,当您真正期望每秒一万个请求时,登录到终端可能不是一个好主意。

于 2014-08-27T16:25:21.317 回答