Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 如何将父异步与多个子异步链接_Multithreading_Haskell_Asynchronous_Concurrency - Fatal编程技术网

Multithreading 如何将父异步与多个子异步链接

Multithreading 如何将父异步与多个子异步链接,multithreading,haskell,asynchronous,concurrency,Multithreading,Haskell,Asynchronous,Concurrency,的文档将withAsync功能描述为: 在单独的线程中生成异步操作,并传递其异步 提供的函数的句柄。当函数返回或抛出 在异步服务器上调用了一个异常,即不间断取消。这是一个 async的有用变体,确保async永远不会停止运行 无意中 在过去的两个小时里,我一直在关注这一点,但一直没有弄清楚如何启动一个监视器线程,该线程会产生多个工作线程,例如: 如果监视器线程死亡,则应终止所有工作线程 但是,如果任何工作线程死亡,其他工作线程都不会受到影响。应该通知监视器,并且它应该能够重新启动工作线程 我们

的文档将
withAsync
功能描述为:

在单独的线程中生成异步操作,并传递其异步 提供的函数的句柄。当函数返回或抛出 在异步服务器上调用了一个异常,即不间断取消。这是一个 async的有用变体,确保async永远不会停止运行 无意中

在过去的两个小时里,我一直在关注这一点,但一直没有弄清楚如何启动一个监视器线程,该线程会产生多个工作线程,例如:

  • 如果监视器线程死亡,则应终止所有工作线程
  • 但是,如果任何工作线程死亡,其他工作线程都不会受到影响。应该通知监视器,并且它应该能够重新启动工作线程

    • 我们似乎需要两个功能:一个启动所有异步任务,另一个监视它们并在它们死时重新启动

      第一个可以这样写:

      withAsyncMany :: [IO t] -> ([Async t] -> IO b) -> IO b
      withAsyncMany []     f = f []
      withAsyncMany (t:ts) f = withAsync t $ \a -> withAsyncMany ts (f . (a:))
      
      import Control.Monad.Managed (with,managed)
      
      withAsyncMany' :: [IO t] -> ([Async t] -> IO b) -> IO b
      withAsyncMany' = with . traverse (\t -> managed (withAsync t))
      
      如果我们使用这个包,我们也可以这样写:

      withAsyncMany :: [IO t] -> ([Async t] -> IO b) -> IO b
      withAsyncMany []     f = f []
      withAsyncMany (t:ts) f = withAsync t $ \a -> withAsyncMany ts (f . (a:))
      
      import Control.Monad.Managed (with,managed)
      
      withAsyncMany' :: [IO t] -> ([Async t] -> IO b) -> IO b
      withAsyncMany' = with . traverse (\t -> managed (withAsync t))
      
      restart函数将循环异步列表,轮询它们的状态,并在它们失败时更新它们:

      {-# language NumDecimals #-}
      import Control.Concurrent (threadDelay)
      
      resurrect :: IO t -> [Async t] -> IO ()
      resurrect restartAction = go []
          where
          go ts [] = do
              threadDelay 1e6    -- wait a little before the next round of polling
              go [] (reverse ts)
          go past (a:pending) = do
              status <- poll a   -- has the task died, or finished?
              case status of
                  Nothing -> go (a:past) pending
                  Just _  -> withAsync restartAction $ \a' -> go (a':past) pending
      
      {-#语言NumDecimals}
      导入控制。并发(线程延迟)
      复活::IO t->[Async t]->IO()
      重新启动操作=继续[]
      哪里
      去做某事
      threadDelay 1e6--在下一轮轮询之前稍等片刻
      go[](反向ts)
      通过(a:待定)=完成
      状态go(a:过去)待定
      Just->withAsync RestarAction$\a'->go(a):过去)挂起
      
      然而,我担心许多嵌套的
      withAsync
      可能会导致某种类型的资源泄漏(因为必须为每个
      withAsync
      安装某种类型的异常处理程序,以便在父线程死亡时通知子线程)


      因此,在这种情况下,最好使用纯
      async
      s生成worker,将
      async
      s的集合存储到某种可变引用中,并在监视器线程中安装一个异常处理程序,它将遍历终止每个任务的容器,使用
      async
      而不是
      withAsync
      。主要功能是

      monitor :: Int -> IO () -> IO ()
      monitor count task =
          bracket (do asyncs <- replicateM count (async task)
                      newIORef asyncs)
                  (\ref -> forever (do
                      threadDelay 1e6
                      asyncs <- readIORef ref
                      vivify task (writeIORef ref) asyncs))
                  (\ref -> do
                      asyncs <- readIORef ref
                      mapM_ uninterruptibleCancel asyncs)
      

      我们在创建新的
      Async
      和将其“持久化”到
      IOref
      之间的时间间隔内屏蔽异步异常,因为否则,如果异步异常在这两者之间到达并终止监视线程,那么
      Async
      将保持悬空状态

      好奇:你的用例是什么?听起来您正试图构建一个Erlang式的监管模型,对于该模型,像@BenjaminHodgson这样的参与者库可能会更好地为您服务。该用例是在我的webapp启动时生成一个作业队列。作业队列在内部生成作业轮询线程和作业侦听/通知线程。如果这些线程中的任何一个死亡,则需要重新生成它们。如果应用程序线程被终止,则需要终止作业队列。