Я пишу программу, в которой большое количество агентов слушает события и реагирует на них. Поскольку Control.Concurrent.Chan.dupChan
устарел, я решил использовать TChan как рекламируемый.
Производительность TChan намного хуже, чем я ожидал. У меня есть следующая программа, которая иллюстрирует проблему:
{-# LANGUAGE BangPatterns #-}
module Main where
import Control.Concurrent.STM
import Control.Concurrent
import System.Random(randomRIO)
import Control.Monad(forever, when)
allCoords :: [(Int,Int)]
allCoords = [(x,y) | x <- [0..99], y <- [0..99]]
randomCoords :: IO (Int,Int)
randomCoords = do
x <- randomRIO (0,99)
y <- randomRIO (0,99)
return (x,y)
main = do
chan <- newTChanIO :: IO (TChan ((Int,Int),Int))
let watcher p = do
chan' <- atomically $ dupTChan chan
forkIO $ forever $ do
[email protected](p',_counter) <- atomically $ readTChan chan'
when (p == p') (print r)
return ()
mapM_ watcher allCoords
let go !cnt = do
xy <- randomCoords
atomically $ writeTChan chan (xy,cnt)
go (cnt+1)
go 1
Когда скомпилировано (-O) и запускается программа, сначала выводится что-то вроде этого:
./tchantest ((0,25),341) ((0,33),523) ((0,33),654) ((0,35),196) ((0,48),181) ((0,48),446) ((1,15),676) ((1,50),260) ((1,78),561) ((2,30),622) ((2,38),383) ((2,41),365) ((2,50),596) ((2,57),194) ((3,19),259) ((3,27),344) ((3,33),65) ((3,37),124) ((3,49),109) ((3,72),91) ((3,87),637) ((3,96),14) ((4,0),34) ((4,17),390) ((4,73),381) ((4,74),217) ((4,78),150) ((5,7),476) ((5,27),207) ((5,47),197) ((5,49),543) ((5,53),641) ((5,58),175) ((5,70),497) ((5,88),421) ((5,89),617) ((6,0),15) ((6,4),322) ((6,16),661) ((6,18),405) ((6,30),526) ((6,50),183) ((6,61),528) ((7,0),74) ((7,28),479) ((7,66),418) ((7,72),318) ((7,79),101) ((7,84),462) ((7,98),669) ((8,5),126) ((8,64),113) ((8,77),154) ((8,83),265) ((9,4),253) ((9,26),220) ((9,41),255) ((9,63),51) ((9,64),229) ((9,73),621) ((9,76),384) ((9,92),569) ...
И затем, в какой-то момент, перестанет писать что-нибудь, все еще потребляя 100% процессор.
((20,56),186) ((20,58),558) ((20,68),277) ((20,76),102) ((21,5),396) ((21,7),84)
С -пожаром блокировка выполняется быстрее и происходит только после нескольких строк. Он также будет потреблять любое количество ядер, доступных через флаг RTS -N.
Кроме того, производительность кажется довольно низкой - обрабатывается только около 100 событий в секунду.
Является ли это ошибкой в STM или я что-то не понимаю о семантике STM?