Haskell で複数のダウンロードを並行して実行しようとしていますが、通常は Control.Concurrent.Async.mapConcurrently 関数を使用するだけです。ただし、これを行うと最大 3000 の接続が開かれ、Web サーバーがそれらすべてを拒否します。mapConcurrently と同じタスクを実行できますが、一度に開く接続の数を制限する (つまり、一度に 2 つまたは 4 つだけにする) ことはできますか?
2475 次
5 に答える
19
簡単な解決策は、セマフォを使用して同時アクションの数を制限することです。最適ではありません (すべてのスレッドが一度に作成されてから待機します) が、機能します。
import Control.Concurrent.MSem
import Control.Concurrent.Async
import Control.Concurrent (threadDelay)
import qualified Data.Traversable as T
mapPool :: T.Traversable t => Int -> (a -> IO b) -> t a -> IO (t b)
mapPool max f xs = do
sem <- new max
mapConcurrently (with sem . f) xs
-- A little test:
main = mapPool 10 (\x -> threadDelay 1000000 >> print x) [1..100]
于 2013-09-19T15:25:42.407 に答える
9
次のように記述できるpooled-ioパッケージを試すこともできます。
import qualified Control.Concurrent.PooledIO.Final as Pool
import Control.DeepSeq (NFData)
import Data.Traversable (Traversable, traverse)
mapPool ::
(Traversable t, NFData b) =>
Int -> (a -> IO b) -> t a -> IO (t b)
mapPool n f = Pool.runLimited n . traverse (Pool.fork . f)
于 2014-01-17T16:54:41.390 に答える
3
Control.Concurrent.Spawn
これは、ライブラリを使用して非常に簡単に実行できます。
import Control.Concurrent.Spawn
type URL = String
type Response = String
numMaxConcurrentThreads = 4
getURLs :: [URL] -> IO [Response]
getURLs urlList = do
wrap <- pool numMaxConcurrentThreads
parMapIO (wrap . fetchURL) urlList
fetchURL :: URL -> IO Response
于 2016-03-20T22:50:34.483 に答える
0
リストにアクションがある場合、これは依存関係が少ない
import Control.Concurrent.Async (mapConcurrently)
import Data.List.Split (chunksOf)
mapConcurrentChunks :: Int -> (a -> IO b) -> [a] -> IO [b]
mapConcurrentChunks n ioa xs = concat <$> mapM (mapConcurrently ioa) (chunksOf n xs)
編集:少し短くしました
于 2014-01-17T18:10:14.980 に答える