hgearman工人如何工作?

问题描述:

三周前我问了一个问题how does hgearman-client work?。通过一些帮助我写了一个简单的客户端应用程序,现在我正在工作。下面的工作者实现很好地编译并运行,没有任何异常。唯一的麻烦是W.runWorker gc (return g)不会被执行。如果我理解正确,这是Haskell懒惰和Monad包装的结果。但我没有想到如何摆脱这个问题。有人能帮忙吗?hgearman工人如何工作?

import qualified Control.Monad.State as S 
import qualified Data.ByteString.Char8 as B 
import qualified Network.Gearman.Client as C 
import qualified Network.Gearman.Worker as W 
import Network.Gearman.Internal (Function, Port) 
import Network.Socket (HostName) 

main :: IO() 
main = do 
    c <- connect 
    case c of 
    Left e -> error $ B.unpack e 
    Right gc -> do 
     (res, _) <- flip S.runStateT gc $ do 
     g <- (W.registerWorker name func) 
     let t = W.runWorker gc (return g) 
     return t >> return() 

     return res 
    where 
    connect = C.connectGearman (B.pack "i") host port 
    host = "localhost"::HostName 
    port = 4730::Port 
    name = (B.pack "foo")::Function 
    func _ = B.pack "bar" 

不幸的是,绑定t <- W.runWorker的尝试以编译器异常结束。如果我这样更改代码:

Right gc -> do 
    (res, _) <- flip S.runStateT gc $ do 
    g <- (W.registerWorker name func) 
    t <- W.runWorker gc (return()) 
    return t >> return () 

    return res 

编译失败,出现异常:

Couldn't match expected type `S.StateT 
           Network.Gearman.Internal.GearmanClient IO a0' 
       with actual type `IO GHC.Conc.Sync.ThreadId' 
    In a stmt of a 'do' block: t <- W.runWorker gc (return()) 
    In the second argument of `($)', namely 
     `do { g <- (W.registerWorker name func); 
      t <- W.runWorker gc (return()); 
      return t >> return() }' 

IO GHC.Conc.Sync.ThreadIdrunWorker结果。

最后我在哈斯克尔实现了一个齿轮工人。

{-# LANGUAGE DeriveDataTypeable #-} 
import Control.Exception (Exception, IOException, catch, throwIO) 
import qualified Data.ByteString.Char8 as B 
import Control.Monad.State 
import Data.Typeable  (Typeable) 
import qualified Network.Gearman.Client as C 
import qualified Network.Gearman.Worker as W 
import Network.Gearman.Internal (Function, GearmanClient, Port) 
import Network.Socket (HostName) 
import   Control.Concurrent 
import qualified Control.Monad.State as S 

data ConnectException = ConnectException HostName Port IOException 
    deriving (Show, Typeable) 
instance Exception ConnectException 

main :: IO() 
main = do 
    c <- connect 
    gc <- either (error . B.unpack) return c 
    work gc 
    return() 
    where 
    connect = C.connectGearman (B.pack "worker-id") host port `catch` \e -> throwIO (ConnectException host port e) 
    host = "localhost"::HostName 
    port = 4730::Port 

work :: GearmanClient -> IO() 
work gc = do 
     (res, _) <- flip S.runStateT gc $ do 
      W.registerWorker (B.pack "reverse"::Function) B.reverse 
      S.get >>= (\env -> forever $ S.liftIO (W.runWorker env (return()) >> threadDelay (1000*1000))) 
      return() 
     return res 

对于某些aGearman a类型的值是动作,做一些事情的食谱。您可以将绑定到这样的食谱来制作更大的食谱,直到您构建了main配方,这是一个可以运行的食谱。

实事求是地讲,这意味着,如果你正在运行一个做块,看起来像这样:

do ... 
    foo 
    ... 

然后foo将运行。如果你有一个做块,看起来像这样:

do ... 
    ret <- foo 
    ... 

然后foo将运行和运行foo的结果将被存储在RET。这两种语法都是绑定的。不过,如果你正在运行一个做块,看起来像这样:

do ... 
    let ret = foo 
    ... 

然后foo将不会运行 - 而不是你只是要求变量ret被简写foo,所以fooret是事后互换。

所以,现在你可以看到,在:

do g <- W.registerWorker name func 
    let t = W.runWorker gc (return g) 
    return t >> return() 

第二线实际上并不运行一个工人,它只是让t有用于运行一个工人的简写。返回一个动作也不会绑定它。您需要绑定:

t <- W.runWorker gc (return g) 

顺便说一句,我一直在寻找的文件,它看起来像registerWorker返回Gearman(),这意味着运行的操作的结果是(),或者“什么有趣” 。所以g是什么有趣的,你可以摆脱它,说

do W.registerWorker name func 
    t <- W.runWorker gc (return()) 
    return t >> return() 
在地方 return()

想必在第二行,你会把你想在工作人员执行的操作。像:

t <- W.runWorker gc $ do 
     ... the things you want the worker to do ... 
    return t >> return() 

最后最后一行:return t >> return(),还写

do return t 
    return() 

是完全一样的东西return()return x构造一个没有副作用的动作,仅用于结果。然后,当您使用>>(或不绑定do块中的结果)时,只会针对其副作用运行操作并放弃其结果。所以第一个return什么都不做。

+0

我真的很感激你的详细答案。我也试过't palik