2

我有一个f返回一个大整数的函数。快结束时,程序必须将所有返回的值相加f。这台计算机的物理内存太有限,无法存储 的所有返回值f。所以我需要把它放到一个文件缓冲区中。TVars 能够处理整数吗?有没有可以抛出所有返回值的解决方案f?此外,单独的线程是否能够同时读取和缓冲它?

4

2 回答 2

1

你对你想做的事情的描述有点模糊,所以我可能需要更多的信息和更多的问题才能达到你的需要。

你的第一个问题:

TVars 能够处理整数吗?

有答案“是”。您可以在 a 中存储任何值TVar,但不能存储未装箱的值(未装箱的值是 GHC 扩展,它公开了一些实现并在类型中有 # 符号)。

有没有一个解决方案可以抛出 f 的所有返回值?

我想“投掷”的意思是“加起来”?如果是这样,那么您可以将运行总计保存在可变变量中,例如TVarorMVar或(如果单线程或非常小心)an IOVar

请注意,存储“x + y”存储“(+)”应用于“x”和“y”,这是一个惰性重击。在将其存储到可变变量之前,您需要强制添加到弱头正常形式 (WHNF)。

此外,单独的线程是否能够同时读取和缓冲它?

这个问题中的“缓冲区”是什么意思?我猜不透。

如果我在多个并发线程访问的可变变量中保持运行总计,那么我将使用MVar Integer.

于 2012-10-16T10:26:23.553 回答
1

你的问题不是很清楚。据我了解,您需要存储函数 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线程完成写入磁盘,但基本上就是这样。

希望这能回答你的问题。

于 2012-10-16T19:07:57.420 回答