我有一个f函数,它返回一个大整数。接近尾声时,程序必须将f的所有返回值相加。此计算机的物理内存太有限,无法存储f的所有返回值。所以我需要把它放到一个文件缓冲区中。TVars能够处理整数吗?有没有可以抛出f的所有返回值的解决方案?另外,单独的线程可以同时读取它并缓冲它吗?
发布于 2012-10-17 03:07:57
你的问题不是很清楚。据我所知,您需要存储函数f在程序运行期间返回的所有结果,因为有大量这样的结果,所以您希望将这些结果存储在一个文件中。因为一计算就存储每个结果的效率会很低,所以您希望实现一种形式的缓冲。
如果是这样的话,你可以使用像Chan这样的东西,例如,它是一个无界阻塞先进先出队列。为了回答您的一个问题,这个结构是专门为多个线程的并发访问而设计的。
因此,您可以在调用f的地方运行主程序,并且对于每个调用,您还可以将结果插入到Chan中。您还将产生另一个线程,该线程将不断地从Chan中读取并将结果写入文件中。
现在,如果主线程(调用f的线程)的速率比另一个线程在磁盘上存储结果的速率高得多,那么您就回到了原来的问题,结果堆积在Chan中,并且您在某个时刻仍然没有足够的内存。对于这种特殊情况,您可以使用类似于Chan的BoundedChan,但当通道已满时将在插入时阻塞。在这种情况下,主线程有时可能需要等待写入线程将结果存储在磁盘上,但是您可以保证不会因为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线程完成对磁盘的写入,但基本上就是这样。
希望这能回答你的问题。
发布于 2012-10-16 18:26:24
你对你想要做的事情的描述有点模糊,所以很可能需要更多的信息和更多的问题才能达到你的需要。
你的第一个问题:
TVars能处理整数吗?
答案是“是”。您可以在TVar中存储任何值,但不能存储未装箱的值(未装箱的值是一个GHC扩展,它公开了一些实现并在类型中包含#符号)。
有没有可以抛出f的所有返回值的解决方案?
我想“掷”的意思是“加起来”?如果是这样,那么您可以在一个可变变量中保存一个运行总数,比如TVar或MVar,或者(如果是单线程的,或者非常小心的)一个IOVar。
请注意,存储"x + y“存储了应用于"x”和"y“的"(+)”,这是一个懒惰的thunk。在将其存储在可变变量中之前,您需要强制将其添加到弱头部范式(WHNF)。
还有,独立的线程可以同时读取它并缓冲它吗?
你在这个问题中说的"buffer“是什么意思?我猜不出来。
如果我在一个可由多个并发线程访问的可变变量中保存一个运行总数,那么我将使用MVar Integer。
https://stackoverflow.com/questions/12907212
复制相似问题