我有一个f
返回一个大整数的函数。快结束时,程序必须将所有返回的值相加f
。这台计算机的物理内存太有限,无法存储 的所有返回值f
。所以我需要把它放到一个文件缓冲区中。TVars 能够处理整数吗?有没有可以抛出所有返回值的解决方案f
?此外,单独的线程是否能够同时读取和缓冲它?
2 回答
你对你想做的事情的描述有点模糊,所以我可能需要更多的信息和更多的问题才能达到你的需要。
你的第一个问题:
TVars 能够处理整数吗?
有答案“是”。您可以在 a 中存储任何值TVar
,但不能存储未装箱的值(未装箱的值是 GHC 扩展,它公开了一些实现并在类型中有 # 符号)。
有没有一个解决方案可以抛出 f 的所有返回值?
我想“投掷”的意思是“加起来”?如果是这样,那么您可以将运行总计保存在可变变量中,例如TVar
orMVar
或(如果单线程或非常小心)an IOVar
。
请注意,存储“x + y”存储“(+)”应用于“x”和“y”,这是一个惰性重击。在将其存储到可变变量之前,您需要强制添加到弱头正常形式 (WHNF)。
此外,单独的线程是否能够同时读取和缓冲它?
这个问题中的“缓冲区”是什么意思?我猜不透。
如果我在多个并发线程访问的可变变量中保持运行总计,那么我将使用MVar Integer
.
你的问题不是很清楚。据我了解,您需要存储函数 f 在程序运行期间返回的所有结果,并且由于有大量此类结果,您希望将这些结果存储在文件中。由于在计算结果后立即实际存储每个结果是低效的,因此您希望实现一种缓冲形式。
如果是这种情况,您可以使用像Chan这样的东西,它是一个无界阻塞 FIFO 队列。为了回答您的一个问题,这个结构是专门为来自多个线程的并发访问而设计的。
所以你可以在你调用 f 的地方运行你的主程序,并且对于每个调用,你也可以将结果插入到 Chan 中。您还将生成另一个线程,该线程将不断地从 Chan 中读取并将结果写入文件中。
现在,如果主线程(调用 f 的线程)的速率远高于另一个线程将结果存储在磁盘上的速率,那么您又回到了原来的问题,即结果堆积在 Chan 和你在某些时候仍然没有记忆。对于这种特殊情况,您可以使用类似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
线程完成写入磁盘,但基本上就是这样。
希望这能回答你的问题。