我有一个f
函数,它返回一个大的整数。接近结束时,程序必须将f
的所有返回值相加。此计算机的物理内存太有限,无法存储f
的所有返回值。所以我需要将它放入文件缓冲区。 TVars能够处理整数吗?有没有一个解决方案,我可以抛出f
的所有返回值?另外,单独的线程是否能够读取它并同时缓冲它?
答案 0 :(得分:1)
您对自己想要做的事情的描述有点模糊,所以我很可能需要更多信息和更多问题才能达到您的需要。
你的第一个问题:
TVars能够处理整数吗?
答案是“是”。您可以将任何值存储在TVar
中,但不能存储在未装箱的值中(未装箱的值是GHC扩展,它会公开某些实现并在类型中包含#符号)。
是否有一个解决方案,我可以抛出f的所有返回值?
我认为“扔”意味着“加起来”?如果是这样,那么您可以在TVar
或MVar
或(如果是单线程或非常小心)IOVar
等可变变量中保留一个总计。
注意,存储“x + y”存储应用于“x”的“(+)”和作为懒惰thunk的“y”。在将其存储在可变变量中之前,您需要强制添加到弱头正常形式(WHNF)。
此外,单独的线程是否能够读取它并缓冲它 在同一时间?
这个问题中“缓冲区”是什么意思?我无法猜测。
如果我在多个并发线程访问的可变变量中保持运行总计,那么我将使用MVar Integer
。
答案 1 :(得分:1)
你的问题并不是那么清楚。根据我的理解,您需要存储函数f在程序运行期间返回的所有结果,并且由于存在大量此类结果,因此您希望将这些结果存储在文件中。由于在计算每个结果后实际存储它是低效的,因此您希望实现一种缓冲形式。
如果是这种情况,您可以使用类似Chan的内容,例如无限制的阻塞FIFO队列。为了回答您的一个问题,这个结构专门设计用于从多个线程进行并发访问。
所以你可以运行你的主程序,你可以调用f,对于每个调用,你也可以将结果插入到Chan中。您还会生成另一个将继续从Chan读取并将结果写入文件的线程。
现在,如果主线程(调用f的线程)的速率远高于另一个线程将结果存储在磁盘上的速率,那么您将回到原来的问题,其结果堆积在陈和你在某些时候仍然记忆犹新。对于这种特殊情况,你可以使用像BoundedChan这样的东西,它类似于Chan,但是当频道已满时会阻塞插入。在这种情况下,主线程有时可能需要等待写入线程将结果存储在磁盘上,但您可以保证永远不会用f的许多结果填充内存。
我们实际上可以为此构建一个很好的抽象。我们可以想象一个函数traceable
给出一个函数f和一个存储值的方法给我们一个函数,它返回与f相同的结果,但作为副作用,它还存储结果供以后分析。
traceable :: (a -> b) -> (b -> IO ()) -> (a -> IO b)
traceable f store = \x -> do
let result = f x
store result
return result
在您的情况下,程序看起来像这样:
f :: Int -> Int
f = ... -- implementation of f here
main = do
ch <- newChan
traceableF = traceable f (writeChan ch)
forkIO $ resultWriter ch
-- the main program which calls traceableF here ...
resultWriter :: Chan Int -> IO ()
resultWriter ch = do
f <- obtainFileHandler
forever $ do
result <- readChan
writeToFile f result
您可能还需要编写一些逻辑,以便主线程等待resultWriter
线程完成写入磁盘,但基本上就是这样。
希望这能回答你的问题。