hgearman worker 是如何工作的?
How does hgearman worker work?
三周前我问了一个问题。在一些帮助下,我编写了一个简单的客户端应用程序,现在我正在工作人员方面工作。下面的 worker 实现编译良好并且运行无任何异常。唯一麻烦的是W.runWorker gc (return g)
不会被执行。如果我理解正确的话,这是 Haskell 懒惰和 return t
Monad 包装的结果。但我还不知道如何摆脱这个问题。有人可以帮忙吗?
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.
的结果
Gearman a
类型的值对于某些 a
是一个 动作 ,一个做某事的秘诀。您可以 将这些食谱绑定 在一起以制作更大的食谱,直到您构建了 main
食谱,即获得 运行.
的食谱
实际上,这意味着如果您正在 运行ning 一个看起来像这样的 do-block:
do ...
foo
...
那么 foo
将是 运行。如果你有一个看起来像这样的 do-block:
do ...
ret <- foo
...
则foo
会运行,运行宁foo
的结果会存入ret。这两种语法是绑定的。但是,如果您正在 运行ning 一个看起来像这样的 do-block:
do ...
let ret = foo
...
那么 foo
将不会是 运行 —— 相反,您只是要求变量 ret
对于 foo
是 shorthand,所以 foo
和 ret
之后可以互换。
现在您可以看到,在:
do g <- W.registerWorker name func
let t = W.runWorker gc (return g)
return t >> return ()
第二行实际上运行一个工人,它只是让t
成为运行的shorthand宁一个工人。返回一个动作也不绑定它。您需要绑定:
t <- W.runWorker gc (return g)
顺便说一下,我一直在看文档,它看起来像 registerWorker
returns 一个 Gearman ()
,这意味着 运行ning 的结果操作是 ()
,或 "nothing interesting"。所以 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 中实现了 gearman worker。
{-# 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
三周前我问了一个问题W.runWorker gc (return g)
不会被执行。如果我理解正确的话,这是 Haskell 懒惰和 return t
Monad 包装的结果。但我还不知道如何摆脱这个问题。有人可以帮忙吗?
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.
Gearman a
类型的值对于某些 a
是一个 动作 ,一个做某事的秘诀。您可以 将这些食谱绑定 在一起以制作更大的食谱,直到您构建了 main
食谱,即获得 运行.
实际上,这意味着如果您正在 运行ning 一个看起来像这样的 do-block:
do ...
foo
...
那么 foo
将是 运行。如果你有一个看起来像这样的 do-block:
do ...
ret <- foo
...
则foo
会运行,运行宁foo
的结果会存入ret。这两种语法是绑定的。但是,如果您正在 运行ning 一个看起来像这样的 do-block:
do ...
let ret = foo
...
那么 foo
将不会是 运行 —— 相反,您只是要求变量 ret
对于 foo
是 shorthand,所以 foo
和 ret
之后可以互换。
现在您可以看到,在:
do g <- W.registerWorker name func
let t = W.runWorker gc (return g)
return t >> return ()
第二行实际上运行一个工人,它只是让t
成为运行的shorthand宁一个工人。返回一个动作也不绑定它。您需要绑定:
t <- W.runWorker gc (return g)
顺便说一下,我一直在看文档,它看起来像 registerWorker
returns 一个 Gearman ()
,这意味着 运行ning 的结果操作是 ()
,或 "nothing interesting"。所以 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 中实现了 gearman worker。
{-# 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