在STM TVar中使用Integer是一个好主意吗?

时间:2012-10-16 03:39:58

标签: multithreading haskell

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

2 个答案:

答案 0 :(得分:1)

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

你的第一个问题:

  

TVars能够处理整数吗?

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

  

是否有一个解决方案,我可以抛出f的所有返回值?

我认为“扔”意味着“加起来”?如果是这样,那么您可以在TVarMVar或(如果是单线程或非常小心)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线程完成写入磁盘,但基本上就是这样。

希望这能回答你的问题。