我一直试图了解并发性,并且我一直在努力找出更好的,一个大IORef锁或许多TVar.我已经达到了以下指导原则,评论将会受到赞赏,关于这些是否大致正确或是否我错过了这一点.
让我们假设我们的并发数据结构是一个地图m,访问类似m[i].让我们说我们有两个功能,f_easy和f_hard.该f_easy快,f_hard需要很长的时间.我们假设参数f_easy/f_hard是元素m.
(1)如果您的交易看起来大致如此m[f_easy(...)] = f_hard(...),请使用IORefwith atomicModifyIORef.懒惰将确保m仅在短时间内锁定,因为它更新了thunk.计算索引有效地锁定了结构(因为某些内容会更新,但我们还不知道是什么),但是一旦知道该元素是什么,整个结构上的thunk就会移动到thunk上,而不是特定元素,然后只有那个特定元素被"锁定".
(2)如果您的交易看起来大致如此m[f_hard(...)] = f_easy(...),并且不要过多冲突,请使用大量的TVars.IORef在这种情况下使用an 将有效地使应用程序成为单线程,因为您无法同时计算两个索引(因为在整个结构中将存在未解决的thunk).TVars允许你同时计算两个索引,但是,否定的是,如果两个并发事务都访问同一个元素,其中一个是写入,则必须废弃一个事务,这会浪费时间(这可能是用于别处).如果这种情况发生了很多,你可能会更好地使用来自(通过黑洞)的锁定IORef,但如果它不会发生很多,你将获得更好的与TVars的并行性.
基本上在情况(2)中,IORef你可以获得100%的效率(没有浪费的工作),但只使用1.1个线程,但TVar如果你的冲突数量很少,你可能会获得80%的效率,但使用10个线程,所以你仍然结束即使浪费了工作,也要快7倍.
我做了以下函数,该函数特定于IO monad:
memoIO :: MonadIO m => m a -> IO (m a)
memoIO action = do
ref <- newMVar Nothing
return $ do
x <- maybe action return =<< liftIO (takeMVar ref)
liftIO . putMVar ref $ Just x
return x
Run Code Online (Sandbox Code Playgroud)
用法示例:
main :: IO ()
main = do
p <- memoIO $ putStrLn "hello"
p
p
Run Code Online (Sandbox Code Playgroud)
打印" hello"一次.
我想(一个小小的烦恼)让它尽可能多地工作(不仅仅是IO).
我在hackage上发现了stateref,我的代码看起来像这样:
{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, Rank2Types, UndecidableInstances #-}
import Data.MRef
class (NewMRef r m a, DefaultMRef r …Run Code Online (Sandbox Code Playgroud) 我想知道Haskell中的IORef是否合法使用?更具体地说,如果有人能够解决以下问题或指向适当的地方了解更多信息,我将感激不尽:
如果有人想要在程序中添加状态,那么状态monad不是更好(更纯粹)的方式.如果一个人感觉更加迫切,他还不能继续使用STM和MVar,还能更好吗?
是否有使用IORef而不是STM,MVar或纯IO轻松处理的编程方案?
我正在阅读一篇使用IORef作为代码片段的论文,由于我对IORef的负面看法,我很难读到这篇论文.我不想沉迷于我的无知,而是想让我的同伴Haskellers寻求帮助可能是一个更好的主意.
这对我来说完全是个惊喜。有人可以解释一下在飞行中readIORef阻塞的原因是atomicModifyIORef什么吗?我知道假设是提供给后一个函数的修改函数应该非常快,但这不是重点。
这是一段示例代码,它重现了我所说的内容:
{-# LANGUAGE NumericUnderscores #-}
module Main where
import Control.Concurrent
import Control.Concurrent.Async
import Control.Monad
import Data.IORef
import Say (sayString)
import Data.Time.Clock
import System.IO.Unsafe
main :: IO ()
main = do
ref <- newIORef (10 :: Int)
before <- getCurrentTime
race_ (threadBusy ref 10_000_000) (threadBlock ref)
after <- getCurrentTime
sayString $ "Elapsed: " ++ show (diffUTCTime after before)
threadBlock :: IORef Int -> IO ()
threadBlock ref = do
sayString "Below threads are totally blocked on …Run Code Online (Sandbox Code Playgroud) 我正在开发一个程序,它使用大量IORef的数据类型列表.哪种内存/处理器效率更高的方法:
[IORef Foo]
Run Code Online (Sandbox Code Playgroud)
要么
IORef [Foo]
Run Code Online (Sandbox Code Playgroud)
忽略我使用列表而不是向量或数组的事实.
我正在做一些并发和内存可见性的实验,并遇到了这种奇怪的行为(请参阅注释内联):
module Main
where
import Data.IORef
import Control.Concurrent
import System.CPUTime
import System.IO
main = do
hSetBuffering stdout NoBuffering
r <- newIORef False
putStrLn "forking..." -- PRINTED
forkIO $ f r
threadDelay 1000000
putStrLn "writeIORef" -- NEVER PRINTED
writeIORef r True
threadDelay maxBound
f :: IORef Bool -> IO ()
f r = readIORef r >>= \b-> if b then print "NEVER PRINTED" else f r
Run Code Online (Sandbox Code Playgroud)
我希望writeIORef孩子线程可能看不到,但主线程不能简单地(显然)停止.
编译于ghc 7.8.3
cabal exec ghc -- --make -fforce-recomp -O2 -threaded visibility.hs
Run Code Online (Sandbox Code Playgroud)
并运行 …
我是一名开始学习Haskell的Schemer.我正在尝试在SICP的第4章之后在C中实现Scheme解释器.事实证明直接用C编程太难了.所以我决定先在Haskell中进行原型设计.在48小时内自己编写一个方案的帮助下,我已经实现了除变量,闭包和环境之外的所有功能.
修改IORef不会在调用之间持续存在main.我希望程序打印(False)(True)(True)(True) ...但实际上它打印(False)(True)(False)(True)(False)(True) ...
代码的精简版:
import Data.IORef
data SCM = Environment (IORef Bool) SCM | Empty'Environment
global :: IO SCM
global = Environment <$> newIORef False <*> pure Empty'Environment
print'' :: SCM -> IO ()
print'' ls =
case ls of
Empty'Environment -> pure ()
Environment first rest -> readIORef first >>= putStr . show >> print'' rest
print' :: SCM -> IO ()
print' ls = putStr …Run Code Online (Sandbox Code Playgroud) 我找到了一些示例代码,并稍微改了一下
counter = unsafePerform $ newIORef 0
newNode _ = unsafePerformIO $
do
i <- readIORef counter
writeIORef counter (i+1)
return i
Run Code Online (Sandbox Code Playgroud)
每次运行时返回1然后2然后3然后3等.
但是当我改变它
newNode = unsafePerformIO $
do
i <- readIORef counter
writeIORef counter (i+1)
return i
Run Code Online (Sandbox Code Playgroud)
然后我每次运行都得0.
为什么会发生这种情况,我该怎么做才能解决这个问题?
设置:
我有几个各种数据结构的集合,代表虚拟系统中模拟对象的状态.我还有许多函数可以转换(即基于原始对象和0或更多参数创建对象的新副本)这些对象.
目标是允许用户选择一些对象来应用转换(在模拟规则内),将这些函数应用于这些对象,并通过用新的对象替换旧对象来更新集合.
我希望能够通过将较小的变换组合成较大的变换来构建这种类型的函数.然后评估这个组合功能.
问题:
如何构建我的程序以使其成为可能?
我用什么样的组合来建立像这样的交易?
想法:
1和2看起来像是带着很多行李,特别是如果我想最终将一些集合移动到数据库中.(Darn IO Monad)
3似乎运作良好但开始看起来很像重新创建OOP.我也不确定在什么级别使用IORef.(例如IORef (Collection Obj)或Collection (IORef Obj)或data Obj {field::IORef(Type)} )
4感觉功能最强大,但它似乎也创造了很多代码复杂性而在表现力方面没有太大的回报.
例
我有一个网店前面.我维护了一系列产品,其中包括库存数量和价格(等等).我还有一些对商店有信用的用户.
用户出现并选择3个产品购买并使用商店信用结账.我需要创建一个新产品集合,其中有3个产品的库存量减少,创建一个新的用户集合,用户帐户借记.
这意味着我得到以下内容:
checkout :: Cart -> ProductsCol -> UserCol -> (ProductsCol, UserCol)
Run Code Online (Sandbox Code Playgroud)
但是生活变得更复杂,我需要处理税收:
checkout :: Cart -> ProductsCol -> UserCol -> TaxCol
-> (ProductsCol, UserCol, TaxCol)
Run Code Online (Sandbox Code Playgroud)
然后我需要确保将订单添加到发货队列:
checkout :: Cart
-> ProductsCol
-> UserCol
-> TaxCol
-> ShipList
-> (ProductsCol, UserCol, TaxCol, ShipList)
Run Code Online (Sandbox Code Playgroud)
等等...
我想写的是类似的东西
checkout …Run Code Online (Sandbox Code Playgroud) 在 GHCI(版本 9.0.1)中,以下内容返回了我所期望的内容:
ghci> import Data.IORef
ghci> ref <- newIORef ([] :: [Int])
ghci> modifyIORef ref (1:)
ghci> readIORef ref
[1]
Run Code Online (Sandbox Code Playgroud)
但是当我以这种方式尝试同样的事情时:
ghci> import Data.IORef
ghci> ref = newIORef ([] :: [Int])
ghci> ref >>= \r -> modifyIORef r (1:)
ghci> ref >>= readIORef
[]
Run Code Online (Sandbox Code Playgroud)
返回一个空列表,就好像修改从未发生过一样。为什么会出现这种情况?输出不应该是一样的吗?