2017-04-01 107 views
1

三週前我問了一個問題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結果。

回答

0

最後我在哈斯克爾實現了一個齒輪工人。

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

對於某些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 < - W.runWorker gc(return g)'。不幸的是,在這種情況下,編譯器抱怨「無法匹配預期的類型」。這就是我轉向讓+返回的原因。我會將代碼段和異常添加到我的問題中。 – palik