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.ThreadId
是runWorker结果。
最后我在哈斯克尔实现了一个齿轮工人。
{-# 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
对于某些a
Gearman a
类型的值是动作,做一些事情的食谱。您可以将绑定到这样的食谱来制作更大的食谱,直到您构建了main
配方,这是一个可以运行的食谱。
实事求是地讲,这意味着,如果你正在运行一个做块,看起来像这样:
do ...
foo
...
然后foo
将运行。如果你有一个做块,看起来像这样:
do ...
ret <- foo
...
然后foo
将运行和运行foo
的结果将被存储在RET。这两种语法都是绑定的。不过,如果你正在运行一个做块,看起来像这样:
do ...
let ret = foo
...
然后foo
将不会运行 - 而不是你只是要求变量ret
被简写foo
,所以foo
和ret
是事后互换。
所以,现在你可以看到,在:
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
什么都不做。
我真的很感激你的详细答案。我也试过't palik