我有一个函数a f
,它返回一个大整数。接近结束时,程序必须将 f
的所有返回值相加。该计算机的物理内存太有限,无法存储 f
的所有返回值。所以我需要将其放入文件缓冲区中。 TVar 能够处理整数吗?有没有一种解决方案可以抛出 f
的所有返回值?另外,单独的线程可以同时读取它并缓冲它吗?
最佳答案
你的问题不太清楚。据我了解,您需要存储函数 f 在程序运行期间返回的所有结果,并且由于存在大量此类结果,您希望将这些结果存储在文件中。由于在计算后立即实际存储每个结果的效率很低,因此您希望实现某种形式的缓冲。
如果是这种情况,您可以使用类似 Chan 的内容例如,这是一个无界阻塞 FIFO 队列。为了回答您的问题之一,该结构是专门为多线程并发访问而设计的。
因此,您可以在调用 f 的地方运行主程序,并且对于每次调用,您还可以将结果插入 Chan.您还可以生成另一个线程,该线程将连续从 Chan 读取并将结果写入文件中。
现在,如果主线程(调用 f 的线程)的速率远高于另一个线程将结果存储在磁盘上的速率,那么您将回到原来的问题,其中结果堆积在陈和你在某些时候仍然会被遗忘。对于这种特殊情况,您可以使用类似 BoundedChan 的内容。与 Chan 类似,但当 channel 已满时会在插入时阻塞。在这种情况下,主线程有时可能必须等待写入线程将结果存储到磁盘上,但您可以保证永远不会用 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
线程完成写入磁盘,但基本上就是这样。
希望这能回答您的问题。
关于multithreading - 在 STM TVar 中使用整数是个好主意吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12907212/