hgearman工人如何工作?



三周前,我问了一个问题,hgearman-client是如何工作的?在一些帮助下,我编写了一个简单的客户端应用程序,我现在正在工作线程端工作。下面的 worker 实现编译良好,运行无异常。唯一的麻烦是W.runWorker gc (return g)不会被执行。如果我理解正确的话,这是Haskell懒惰和return tMonad包装的结果。但是我还没有最模糊的想法如何摆脱这个问题。有人可以帮忙吗?

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 的结果。

对于某些a来说,类型Gearman a的值是一种操作,一种做某事的秘诀。 您可以将这些配方绑定在一起以制作更大的配方,直到您构建了运行main配方。

实际上,这意味着如果您正在运行如下所示的do块:

do ...
foo
...

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

do ...
ret <- foo
...

然后foo将运行,运行foo的结果将存储在 RET 中。 这两种语法是绑定。 但是,如果您正在运行如下所示的 do 块:

do ...
let ret = foo
...

然后foo将不会运行 - 相反,您只是要求变量retfoo的简写,因此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什么也没做。

最后,我在 Haskell 中实现了一个齿轮工。

{-# 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

相关内容

  • 没有找到相关文章

最新更新