代码之家  ›  专栏  ›  技术社区  ›  paul

Haskell中的阻塞线程

  •  0
  • paul  · 技术社区  · 6 年前

    forkIO 哪个创造了一条绿色的线(对吗?是绿线吗?)然后我用一个 MVar

    responseUsers :: ActionM ()
    responseUsers = do emptyVar <- liftAndCatchIO $newEmptyMVar
                       liftAndCatchIO $ forkIO $ do
                                                 users <- getAllUsers
                                                 putMVar emptyVar users
                       users <- liftAndCatchIO $ takeMVar emptyVar
                       json (show users) 
    

    阅读后 我可以看到的类是一个块线程类,如果MVar为空,则阻塞线程直到被填充为止。

    我来自 Scala 在其他的do-avoid块中,我们在未来对象中有回调的概念,其中 A B 得到一个 Future .

    onComplete 一旦线程 以值结束。

    但在那段时间里,丝 一个

    例如,在我们的Http服务器框架中 Vertx Grizzly 通常配置为有少量的操作系统线程(4-8),因为它们永远不应该被阻塞。

    我们不是在哈斯克尔有另一个纯粹的无阻塞机制吗?

    1 回复  |  直到 6 年前
        1
  •  4
  •   K. A. Buhr    6 年前

    好吧,这里有很多东西要拆。首先,让我们讨论一下您的特定代码示例。正确的写作方法 responseUsers 斯科蒂的经纪人是:

    responseUsers :: ActionM ()
    responseUsers = do
      users <- getAllUsers
      json (show users)
    

    getAllUsers 运行一天半,100个客户都在 获得诱惑者

    {-# LANGUAGE OverloadedStrings #-}
    
    import Web.Scotty
    import Control.Concurrent
    import Control.Monad.IO.Class
    import qualified Data.Text.Lazy as T
    
    main = scotty 8080 $ do
      get "/fast" $ html "<h1>Fast Response</h1><p>I'm ready!"
      get "/slow" $ liftIO (threadDelay 30000000) >> html "<h1>Slow</h1><p>Whew, finally!"
      get "/pure" $ html $ "<h1>Answer</h1><p>The answer is " 
                    <> (T.pack . show . sum $ [1..1000000000])
    

    如果编译并启动它,可以打开多个浏览器选项卡:

    http://localhost:8080/slow
    http://localhost:8080/pure
    http://localhost:8080/fast
    

    fast 链接立即返回,即使 slow pure threadDelay --它可能是任何IO操作,如访问数据库或读取大文件或代理到另一个HTTP服务器或其他。)您可以继续为 快速的 , ,和 ,当服务器继续接受更多请求时,速度较慢的服务器将在后台运行。(在 纯净的 计算与 缓慢的 计算——它只会第一次阻塞,等待它的所有线程将立即返回一个答案,随后的请求将很快。如果我们诱使Haskell为每个请求重新计算它,或者它实际上依赖于请求中提供的一些信息,就像在更实际的服务器中那样,它的行为或多或少类似于 不过,还是要计算。)

    这里不需要任何回调,也不需要主线程“等待”结果。Scotty分叉处理每个请求的线程可以执行所需的任何计算或IO活动,然后直接将响应返回给客户端,而不会影响任何其他线程。

    更重要的是,除非你用 -threaded 它只在一个操作系统线程中运行。 所以,默认情况下,它会在一个操作系统线程中自动执行所有这些操作!

    第二,斯科蒂其实没什么特别的。您应该将Haskell运行时看作是在OS线程机制之上提供了一个线程抽象层,而OS线程是一个不必担心的实现细节(好吧,除了在异常情况下,例如,如果您正在与需要在某些操作系统线程中发生某些事情的外部库交互。

    因此,所有Haskell线程,甚至是“主”线程,都是绿色的,并且运行在一种虚拟机上,这种虚拟机在一个OS线程上运行得很好,不管有多少绿色线程由于什么原因阻塞。

    loop :: IO ()
    loop = do
      req <- getRequest
      forkIO $ handleRequest req
      loop
    

    注意这里不需要回拨。这个 handleRequest

    Scotty基本上是围绕这个模式构建的,因此它自动分派多个请求,而不需要回调或阻塞OS线程。